Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Store functions in a Dictionary

How do I create a Dictionary where I can store functions?

Thanks.

I have about 30+ functions which can be executed from the user. I want to be able to execute the function this way:

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

However, the function signature is not always the same, thus having different amount of arguments.

like image 777
chi Avatar asked Nov 20 '10 15:11

chi


2 Answers

Like this:

Dictionary<int, Func<string, bool>> 

This allows you to store functions that take a string parameter and return boolean.

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

Or if the function is not anonymous:

dico[5] = Foo; 

where Foo is defined like this:

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

UPDATE:

After seeing your update it seems that you don't know in advance the signature of the function you would like to invoke. In .NET in order to invoke a function you need to pass all the arguments and if you don't know what the arguments are going to be the only way to achieve this is through reflection.

And here's another alternative:

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

With this approach you still need to know the number and type of parameters that need to be passed to each function at the corresponding index of the dictionary or you will get runtime error. And if your functions doesn't have return values use System.Action<> instead of System.Func<>.

like image 162
Darin Dimitrov Avatar answered Oct 15 '22 06:10

Darin Dimitrov


However, the function signature is not always the same, thus having different amount of arguments.

Let's start with a few functions defined like this:

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

You really have 2 viable options at your disposal:

1) Maintain type-safety by having clients call your function directly.

This is probably the best solution, unless you have very good reasons for breaking from this model.

When you talk about wanting to intercept function calls, it sounds to me like you're trying to re-invent virtual functions. There's a boat load of ways to get this sort of functionality out of the box, such as inheriting from a base class an overriding its functions.

It sounds to me like you want a class that's more of a wrapper than a derived instance of a base class, so do something like this:

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) OR map the input of your functions to a common interface.

This might work if all of your functions are related. For example, if you're writing a game, and all the functions do something to some part of the player or player's inventory. You'd end up with something like this:

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);     } } 
like image 31
Juliet Avatar answered Oct 15 '22 05:10

Juliet