Как мне создать словарь, в котором я могу хранить функции?
Спасибо.
У меня около 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<>
.источник
Dictionary<int, Delegate>
.Начнем с нескольких функций, определенных следующим образом:
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); } }
источник
object
похоже на то, которое будет передано в новый поток.Эй, надеюсь, это поможет. С какого ты языка?
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"]();
источник