String- Function dictionary c# where functions have different arguments

后端 未结 9 2853
温柔的废话
温柔的废话 2021-02-19 09:13

Basically I\'m trying to make a string to function dictionary in c#, I\'ve seen it done like this:

Dictionary>
<         


        
相关标签:
9条回答
  • 2021-02-19 09:29

    First of all, if you have to use a method dictionary, implement your methods to have the same signature ! (Or really similar whith less diffences possible). If not, you can still transform your method signature with lambda expression.

    Lambda expressions

        static string Method1(string a)
        {
            return a;
        }
    
        static void Method2(string a, string b)
        {
            Console.WriteLine(a + b);
        }
    
        static string Method3(string a, string b, int x)
        {
            return String.Format("a:{0} b:{1} x:{2}", a, b, x);
        }
    
        static int Method4(int x)
        {
            return x;
        }
    
        static void Main(string[] args)
        {
            var methods = new Dictionary<string, Func<int, string, string, string, string>>()
            {
                { "method1", (x, a, b, c) => Method1(a) },
                { "method2", (x, a, b, c) => { Method2(a, b); return ""; } },
                { "method3", (x, a, b, c) => Method3(a, b, x) },
                { "method4", (x, a, b, c) => Method4(x).ToString() },
            };
            foreach (var key in methods.Keys)
                Console.WriteLine(key + ": " + methods[key](1, "a", "b", "c"));
            Console.ReadKey();
        }
    

    As you can see, you will have to maintain the method signature for you dictionary to have all the possible arguments. IT'S UGLY ! But this will work, you won't have to care about which method is behind which string. They will all use the same parameters. But you will have to be very cautious when calling them since, you can easily make a mistake when you call them in the lambda expressions due to the big number of parameters that you will pass.


    Structure/Dictionary argument passing

        struct method_parameters
        {
            public string a;
            public string b;
            public int x;
        }
    
        static string Method1(method_parameters parameters)
        {
            return parameters.a;
        }
    
        static void Method2(method_parameters parameters)
        {
            Console.WriteLine(parameters.a + parameters.b);
        }
    
        static string Method3(method_parameters parameters)
        {
            return String.Format("a:{0} b:{1} x:{2}",
                parameters.a, parameters.b, parameters.x);
        }
    
        static int Method4(method_parameters parameters)
        {
            return parameters.x;
        }
    
        static void Main(string[] args)
        {
            method_parameters parameters = new method_parameters()
            {
                a = "a",
                b = "b",
                x = 1
            };
            var methods = new Dictionary<string, Func<method_parameters, string>>()
            {
                { "method1", Method1 },
                { "method2", (param) => { Method2(param); return ""; } },
                { "method3", Method3 },
                { "method4", (param) => Method4(param).ToString() },
            };
            foreach (var key in methods.Keys)
                Console.WriteLine(key + ": " + methods[key](parameters));
            Console.ReadKey();
        }
    

    This method is easier to maintain, since you will not have to update each method and entries of your dictionary if you have to add/change an argument. You will just have to modify your stucture/class/dictionary depending on what you chose as parameter storage. But to call a method you will have to update your structure first. And clear it if necessary !

    0 讨论(0)
  • 2021-02-19 09:31

    Considering your use case of text based rpg with commands with a set of arguements, perhaps you should make all of your commands methods that all have a signature of

    MethodName(string[] args)
    

    With the Dictionary of

    new Dictionary><string, Action<string[]>>
    

    That would make it easier to work with your dictionary and actually call the methods.

    0 讨论(0)
  • 2021-02-19 09:31

    One possible approach to this problem is to create a wrapper class to your own dictionary that simply stores the function delegates as an object. You can then use generic methods to add a retrieve the function that match your signatures.

    The following code example shows a very basic implementation:

    class FunctionDictionary
    {
        /// <summary>
        /// Internal dictionary that will store the function delegates as Object.
        /// </summary>
        private Dictionary<string, Object> m_Map = new Dictionary<string, object>();
    
        /// <summary>
        /// Add method to dictionary for specified key. Encapsulated method has no parameters.
        /// </summary>
        public void Add<TResult>(string key, Func<TResult> function) 
        {
            m_Map.Add(key, function);
        }
    
        /// <summary>
        /// Get method for specified key. Encapsulated method has no parameters.
        /// </summary>
        public Func<TResult> Function<TResult>(string key)
        {
            return (Func<TResult>)m_Map[key];
        }
    
        /// <summary>
        /// Add method to dictionary for specified key. Encapsulated method has one parameters.
        /// </summary>
        public void Add<T1, TResult>(string key, Func<T1, TResult> function)
        {
            m_Map.Add(key, function);
        }
    
        /// <summary>
        /// Get method for specified key. Encapsulated method has one parameters.
        /// </summary>
        public Func<T, TResult> Function<T, TResult>(string key)
        {
            return (Func<T, TResult>)m_Map[key];
        }
    
    
        public void Add<T1, T2, TResult>(string key, Func<T1, T2, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, TResult>(string key, Func<T1, T2, T3, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, TResult>(string key, Func<T1, T2, T3, T4, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, TResult>(string key, Func<T1, T2, T3, T4, T5, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> function)
        {
            m_Map.Add(key, function);
        }
        public void Add<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(string key, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> function)
        {
            m_Map.Add(key, function);
        }
    
    
        public Object this[string key]
        {
            get
            {
                return m_Map[key];
            }
        }
    
        public Func<T1, T2, TResult> Function<T1, T2, TResult>(string key)
        {
            return (Func<T1, T2, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, TResult> Function<T1, T2, T3, TResult>(string key)
        {
            return (Func<T1, T2, T3, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, TResult> Function<T1, T2, T3, T4, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, TResult> Function<T1, T2, T3, T4, T5, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, TResult> Function<T1, T2, T3, T4, T5, T6, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, TResult> Function<T1, T2, T3, T4, T5, T6, T7, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>)m_Map[key];
        }
        public Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> Function<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(string key)
        {
            return (Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>)m_Map[key];
        }
    
    }
    

    The following code example demonstrates the usage:

    class FunctionMapUsage
    {
        private FunctionDictionary functions = new FunctionDictionary();
        public string FunctionA()
        {
            return "A";
        }
    
        public string FunctionB(int value)
        {
            return value.ToString();
        }
    
        public int FunctionC(string str1, string str2)
        {
            return str1.Length + str2.Length;
        }
    
        public void CreateFunctionMap()
        {
            functions.Add<string>("A", FunctionA);                      // Add Function A to map
            functions.Add<int, string>("B", FunctionB);                 // Add Function B to map
            functions.Add<string, string, int>("C", FunctionC);         // Add Function C to map
        }
    
        public void CallFunctions()
        {
            var functionA = functions.Function<string>("A");                // Get Function A
            var functionB = functions.Function<int, string>("B");           // Get Function B
            var functionC = functions.Function<string, string, int>("C");   // Get Function C
    
            string resultA = functionA();
            string resultB = functionB(123);
            int resultC = functionC("parameter 1", "parameter 2");
        }
    }
    

    The CreateFunctionMap method simply adds new functions to the dictionary. The CallFunctions methods show how to extract and execute functions from the dictionary.

    0 讨论(0)
  • 2021-02-19 09:35

    (edited) One easy but nasty solution could be something like this,

    private void methodDictionary()
    {
        var infos = new Dictionary<string, MethodInfo>();
        infos.Add("a", this.GetType().GetMethod("a"));
        infos.Add("b", this.GetType().GetMethod("b"));
    
        MethodInfo a = infos["a"];
        a.Invoke(this, new[] { "a1", "b1" });
    
        MethodInfo b = infos["b"];
        b.Invoke(this, new object[] { 10, "b1", 2.056 });
    }
    
    public void a(string a, string b)
    {
        Console.WriteLine(a);
        Console.WriteLine(b);
    }
    
    public void b(int a, string b, double c)
    {
        Console.WriteLine(a);
        Console.WriteLine(b);
        Console.WriteLine(c);
    }
    
    0 讨论(0)
  • 2021-02-19 09:40

    You can define your own delegate taking a params string[] argument, like this:

    delegate TOut ParamsFunc<TIn, TOut>(params TIn[] args);
    

    And declares your dictionary like so:

    Dictionary<string, ParamsFunc<string, string>> functions;
    

    So, you can use it like this:

    public static string Concat(string[] args)
    {
        return string.Concat(args);
    }
    
    var functions = new Dictionary<string, ParamsFunc<string, string>>();
    functions.Add("concat", Concat);
    
    var concat = functions["concat"];
    
    Console.WriteLine(concat());                                //Output: ""
    Console.WriteLine(concat("A"));                             //Output: "A"
    Console.WriteLine(concat("A", "B"));                        //Output: "AB"
    Console.WriteLine(concat(new string[] { "A", "B", "C" }));  //Output: "ABC"
    

    Be aware that you still need to declare your methods with a string[] argument, even if you only need one string parameter.

    On the other hand, it can be called using params style (like concat() or concat("A", "B")).

    0 讨论(0)
  • 2021-02-19 09:44

    There are a few ways to accomplish this, but there is a reason there are no good answers. If you were able to do this you would still need more logic around calling the functions, unless your functions were to only have differing numbers of strings. Then each function could do it's own handling of the arguments.

    With that said you could do this:

        public delegate string DelegateAction(params string[] args);
        public Dictionary<string, DelegateAction> Actions = new Dictionary<string, DelegateAction>();
    
        public void InitializeDictionary()
        {
          Actions.Add("walk",Move);
        }
    
    
        public string Move(params string[] args)
        {
          if (args.Length > 0)
          {
            if (!string.IsNullOrWhiteSpace(args[0]))
            {
              switch (args[0].ToLower())
              {
                case "forward":
                  return "You move forward at a leisurely pace";
                case "right":
                case "left":
                case "backward":
                  throw new NotImplementedException("Still need to set these up");
                default:
                  return "You need to specify a valid direction (forward,backward,right,left).";
              }
            }
          }
          return "You need to specify a direction.";
        }
    
        public string ProcessAction(string action, params string[] args)
        {
          return Actions[action.ToLower()].Invoke(args);
        }
    

    Let it be said, if you are going to do this, keys are case sensitive so you will need to use either lowercase/ToLower() or UPPERCASE/ToUpper() for them. You can handle your other parameters many ways, some which you can use other case insensitive matching, but with the switch-case in this example the cases must match also.

    Good Luck!

    0 讨论(0)
提交回复
热议问题