[c#] 사전에 C # 저장소 함수

함수를 저장할 수있는 사전을 어떻게 만듭니 까?

감사.

사용자가 실행할 수있는 기능이 약 30 개 이상 있습니다. 이 방법으로 함수를 실행할 수 있기를 원합니다.

   private void functionName(arg1, arg2, arg3)
   {
       // code
   }

   dictionaryName.add("doSomething", functionName);

    private void interceptCommand(string command)
    {
        foreach ( var cmd in dictionaryName )
        {
            if ( cmd.Key.Equals(command) )
            {
                cmd.Value.Invoke();
            }
        }
    }

그러나 함수 시그니처가 항상 동일한 것은 아니므로 인수의 양이 다릅니다.



답변

이렇게 :

Dictionary<int, Func<string, bool>>

이를 통해 문자열 매개 변수를 취하고 부울을 반환하는 함수를 저장할 수 있습니다.

dico[5] = foo => foo == "Bar";

또는 함수가 익명이 아닌 경우 :

dico[5] = Foo;

Foo는 다음과 같이 정의됩니다.

public bool Foo(string bar)
{
    ...
}

최신 정보:

업데이트를 확인한 후 호출하려는 함수의 서명을 미리 알지 못하는 것 같습니다. .NET에서 함수를 호출하려면 모든 인수를 전달해야하며 인수가 무엇인지 모르는 경우이를 달성하는 유일한 방법은 리플렉션을 사용하는 것입니다.

또 다른 대안이 있습니다.

class Program
{
    static void Main()
    {
        // store
        var dico = new Dictionary<int, Delegate>();
        dico[1] = new Func<int, int, int>(Func1);
        dico[2] = new Func<int, int, int, int>(Func2);

        // and later invoke
        var res = dico[1].DynamicInvoke(1, 2);
        Console.WriteLine(res);
        var res2 = dico[2].DynamicInvoke(1, 2, 3);
        Console.WriteLine(res2);
    }

    public static int Func1(int arg1, int arg2)
    {
        return arg1 + arg2;
    }

    public static int Func2(int arg1, int arg2, int arg3)
    {
        return arg1 + arg2 + arg3;
    }
}

이 접근 방식을 사용하는 경우 사전의 해당 인덱스에서 각 함수에 전달해야하는 매개 변수의 수와 유형을 알아야합니다. 그렇지 않으면 런타임 오류가 발생합니다. 그리고 함수에 반환 값이 없으면 System.Action<>대신 System.Func<>.


답변

그러나 함수 시그니처가 항상 동일한 것은 아니므로 인수의 양이 다릅니다.

다음과 같이 정의 된 몇 가지 함수부터 시작하겠습니다.

private object Function1() { return null; }
private object Function2(object arg1) { return null; }
private object Function3(object arg1, object arg3) { return null; }

당신은 당신의 처분에 실제로 두 가지 실행 가능한 옵션이 있습니다.

1) 클라이언트가 함수를 직접 호출하도록하여 형식 안전성을 유지합니다.

당신이하지 않는 한 이것은 아마 최고의 솔루션입니다 매우 이 모델에서 깨는 좋은 이유.

함수 호출을 가로 채고 싶다고 말할 때, 가상 함수를 다시 발명하려는 것처럼 들립니다. 기본 클래스에서 상속하고 함수를 재정의하는 것과 같이 이러한 종류의 기능을 즉시 사용할 수있는 방법이 많습니다.

기본 클래스의 파생 인스턴스보다 래퍼에가까운 클래스를 원하는 것처럼 들리 므로 다음과 같이하십시오.

public interface IMyObject
{
    object Function1();
    object Function2(object arg1);
    object Function3(object arg1, object arg2);
}

class MyObject : IMyObject
{
    public object Function1() { return null; }
    public object Function2(object arg1) { return null; }
    public object Function3(object arg1, object arg2) { return null; }
}

class MyObjectInterceptor : IMyObject
{
    readonly IMyObject MyObject;

    public MyObjectInterceptor()
        : this(new MyObject())
    {
    }

    public MyObjectInterceptor(IMyObject myObject)
    {
        MyObject = myObject;
    }

    public object Function1()
    {
        Console.WriteLine("Intercepted Function1");
        return MyObject.Function1();
    }
    public object Function2(object arg1)
    {
        Console.WriteLine("Intercepted Function2");
        return MyObject.Function2(arg1);
    }

    public object Function3(object arg1, object arg2)
    {
        Console.WriteLine("Intercepted Function3");
        return MyObject.Function3(arg1, arg2);
    }
}

2) 또는 함수 입력을 공통 인터페이스에 매핑합니다.

모든 기능이 관련된 경우 작동 할 수 있습니다. 예를 들어, 게임을 작성하고 모든 기능이 플레이어 또는 플레이어 인벤토리의 일부에 무언가를 수행하는 경우입니다. 다음과 같은 결과를 얻게됩니다.

class Interceptor
{
    private object function1() { return null; }
    private object function2(object arg1) { return null; }
    private object function3(object arg1, object arg3) { return null; }

    Dictionary<string, Func<State, object>> functions;

    public Interceptor()
    {
        functions = new Dictionary<string, Func<State, object>>();
        functions.Add("function1", state => function1());
        functions.Add("function2", state => function2(state.arg1, state.arg2));
        functions.Add("function3", state => function3(state.arg1, state.are2, state.arg3));
    }

    public object Invoke(string key, object state)
    {
        Func<object, object> func = functions[key];
        return func(state);
    }
}


답변

이게 도움이되기를 바랍니다. 어떤 언어에서 왔습니까?

internal class ForExample
{
    void DoItLikeThis()
    {
        var provider = new StringMethodProvider();
        provider.Register("doSomethingAndGetGuid", args => DoSomeActionWithStringToGetGuid((string)args[0]));
        provider.Register("thenUseItForSomething", args => DoSomeActionWithAGuid((Guid)args[0],(bool)args[1]));


        Guid guid = provider.Intercept<Guid>("doSomethingAndGetGuid", "I don't matter except if I am null");
        bool isEmpty = guid == default(Guid);
        provider.Intercept("thenUseItForSomething", guid, isEmpty);
    }

    private void DoSomeActionWithAGuid(Guid id, bool isEmpty)
    {
        // code
    }

    private Guid DoSomeActionWithStringToGetGuid(string arg1)
    {
        if(arg1 == null)
        {
            return default(Guid);
        }
        return Guid.NewGuid();
    }

}
public class StringMethodProvider
{
    private readonly Dictionary<string, Func<object[], object>> _dictionary = new Dictionary<string, Func<object[], object>>();
    public void Register<T>(string command, Func<object[],T> function)
    {
        _dictionary.Add(command, args => function(args));
    }
    public void Register(string command, Action<object[]> function)
    {
        _dictionary.Add(command, args =>
                                     {
                                         function.Invoke(args);
                                         return null;
                                     } );
    }
    public T Intercept<T>(string command, params object[] args)
    {
        return (T)_dictionary[command].Invoke(args);
    }
    public void Intercept(string command, params object[] args)
    {
        _dictionary[command].Invoke(args);
    }
}


답변

params object[] list메서드 매개 변수에 사용하지 않고 메서드 (또는 호출 논리) 내에서 일부 유효성 검사를 수행하면 가변 개수의 매개 변수가 허용됩니다.


답변

다음 시나리오에서는 요소 사전을 사용하여 입력 매개 변수로 전송하고 출력 매개 변수와 동일하게 가져올 수 있습니다.

먼저 맨 위에 다음 행을 추가하십시오.

using TFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Collections.Generic.IDictionary<string, object>>;

그런 다음 클래스 내에서 다음과 같이 사전을 정의하십시오.

     private Dictionary<String, TFunc> actions = new Dictionary<String, TFunc>(){

                        {"getmultipledata", (input) =>
                            {
                                //DO WORKING HERE
                                return null;
                            }
                         },
                         {"runproc", (input) =>
                            {
                                //DO WORKING HERE
                                return null;
                            }
                         }
 };

이렇게하면 다음과 유사한 구문으로 이러한 익명 함수를 실행할 수 있습니다.

var output = actions["runproc"](inputparam);


답변

사전을 정의하고 System.Action유형으로 사용하여 함수 참조를 값으로 추가합니다 .

using System.Collections;
using System.Collections.Generic;

public class Actions {

    public Dictionary<string, System.Action> myActions = new Dictionary<string, System.Action>();

    public Actions() {
        myActions ["myKey"] = TheFunction;
    }

    public void TheFunction() {
        // your logic here
    }
}

그런 다음 다음을 사용하여 호출하십시오.

Actions.myActions["myKey"]();


답변