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();
}
}
}


однако сигнатура функции не всегда одинакова, поэтому имеет разное количество аргументов.

974   6  

6 ответов:

такой:

Dictionary<int, Func<string, bool>>

это позволяет хранить функции, которые принимают строковый параметр и возвращают логическое значение.

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

или если функция не является анонимным:

dico[5] = Foo;

где Foo определяется следующим образом:

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

обновление:

после просмотра вашего обновления кажется, что вы не знаете заранее подпись функции, которую вы хотели бы вызвать. В .Сетка для того, чтобы вызвать функцию, нужно пройти все Аргументы, и если вы не знаете, какие аргументы будут единственным способом достичь этого, - это отражение.

и вот еще одна альтернатива:

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; }

у вас действительно есть 2 жизнеспособных варианта в вашем распоряжении:

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);
    }
}

почему бы не использовать params object[] list для параметров метода и выполните некоторую проверку внутри ваших методов (или вызывающей логики), это позволит использовать переменное количество параметров.

Эй, я надеюсь, что это помогает. На каком языке ты говоришь?

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);
    }
}

следующий сценарий позволит вам использовать словарь элементов для отправки в качестве входных параметров и получить то же самое, что и выходные параметры.

Сначала добавьте следующую строку вверху:

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"]();

Comments

    Ничего не найдено.