具有指定参数的调用方法

时间:2019-03-16 03:04:22

标签: c#

有一个字典列表,用于逐个存储参数,并且需要由列表中的参数调用方法。有没有简单的方法可以做到这一点?谢谢

IDictionary<string, string> argDict = new Dictionary<string, string>();
argDic.add("a", "100");
argDic.add("b", "200");
argDic.add("c", "300");

private void Run(string a, string b, string c){
    Console.WriteLine("Hello World!");
}

Run(argDic["a"], argDic["b"], argDic["c"]);

这仅是一个示例,字典列表不是固定的,其中有许多随机变量。如果第一个参数“ a”匹配,则将在字典对象中找到该参数,并且将使用字典中的参数“ a”值100。

更新: 对不起,我应该用图片说明。有一个作业计划,计划任务时,应通过其名称和参数调用每个任务节点上的绑定方法。因此,该方法及其参数是通过配置指定的。

enter image description here

**Task001:**
Invoked Method: MethodA(string a, string b, string c);
Variable Key: ["a", "b", "c"]
Variable Value: ["100", "200", "300"]

**Taks002:**
Invoked Method: MethodB(int d, int e);
Variable Key: ["d", "e"]
Variable Value: ["9", "99"]

private void MethodA(string a, string b, string c){
        Console.WriteLine("Hello the string World!");
    }

private void MethodB(int d, int e){
        Console.WriteLine("Hello the int World!");
}

3 个答案:

答案 0 :(得分:-1)

在我看来这是最好的方法:

IDictionary<string, string> argDict = new Dictionary<string, string>()
{
    {   "a", "100" },
    {   "b", "200" },
    {   "c", "300" },
};

IDictionary<string, Action<IDictionary<string, string>>> runDict = new Dictionary<string, Action<IDictionary<string, string>>>()
{
    { "MethodA", d => MethodA(d["a"], d["b"], d["c"]) },
    { "MethodB", d => MethodB(int.Parse(d["d"]), int.Parse(d["e"])) },
}

runDict["MethodA"](argDict);

答案 1 :(得分:-2)

更好的是,您可以拥有一个包含所有可能的参数类型的类,并将该类作为参数传递给方法,这将帮助您避免类型转换,并且稍后您可以将新成员添加到该类中。 例如:

class methodArgs
{
  public int param1 {get;set;}
  public string param2 {get;set;}
  public double param3 {get;set;}
  public bool param4 {get;set;}
}

并将其设置为:

methodArgs obj = new methodArgs();
obj.param1 = 10;
obj.param2 = "Hello World";
obj.param3 = 10.10;
obj.param4 = false;

并像这样传递它:

Run(obj);

答案 2 :(得分:-2)

您说的是一个示例,但是Run方法上定义的实际参数是什么?

您可以使用Reflection动态获取Run方法的MethodInfo并根据当前拥有的数据提供参数,包括检查字典中是否存在特定键。

您可以使用params数组作为输入,并使用该数组来调用Run方法,该方法将定义为:

private void Run(params string[] data) {}

可以与可变数量的参数一起使用:

Run("a", "b");
Run("c", "d", "e");

更新

考虑到您的最新答案,我看到您希望有一个工作分配机制,该机制可以根据方法的名称和一些以文本形式发送的参数来动态调用方法。 C#具有出色的功能,基本上是反射。这是一个说明所有内容的示例,包括使用反射的基本版本(以防万一,您必须使用它)。

借助反射,您还可以检查参数列表,并根据需要根据参数名称进行匹配(以下未显示,请告知是否需要帮助)

/// <summary>
/// Runner should not contain dangerous methods! Access control and security aspects must be considered.
/// </summary>
public class Runner
{
    /// <summary>Just to illustrate</summary>
    public int CallCount { get; set; }

    internal void MethodA(string a, string b, string c)
    {
        CallCount++;
        Console.WriteLine($"Hello the string World {a}, {b}, {c}!");
    }

    internal void MethodB(int d, int e)
    {
        CallCount++;
        Console.WriteLine($"Hello the int World, sum = {d + e}!");
    }

    internal void MethodC(string a, string b, string c, string d, string e)
    {
        CallCount++;
        Console.WriteLine($"Welcome to the world of the strings {a}, {b}, {c}, {d}, {e}!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var instance = new Runner();
        ExecuteMethodWithSwitch(instance, "MethodA", "aaa", "bbb", "ccc");
        ExecuteMethod(instance, "MethodA", "aaa", "bbb", "ccc");
        ExecuteMethod(instance, "MethodB", 111, 222);
        ExecuteMethod(instance, "MethodC", "aaa", "bbb", "ccc", "monkey", "banana");
        //this is a testing-related statement
        System.Diagnostics.Debug.Assert(instance.CallCount == 4, "CallCount should be 4");
        Console.WriteLine($"Instance has been called {instance.CallCount} times...");
    }

    /// <summary>
    /// NOT RECOMMENDED WAY: Just use a switch statement and convert arguments like a noob.
    /// Only good thing about this is perhaps that is has more compile time checks.
    /// Incorrect arguments = exception.
    /// </summary>
    /// <param name="o"></param>
    /// <param name="methodName"></param>
    /// <param name="args"></param>
    private static void ExecuteMethodWithSwitch(Runner runner, string methodName, params object[] args)
    {
        switch (methodName)
        {
            case nameof(runner.MethodA):
                runner.MethodA(args[0]?.ToString(), args[1]?.ToString(), args[2]?.ToString());
                break;
            case nameof(runner.MethodB):
                var int1 = Convert.ToInt32(args[0]);
                var int2 = Convert.ToInt32(args[1]);
                runner.MethodB(int1, int2);
                break;
            case nameof(runner.MethodC):
                runner.MethodC(args[0]?.ToString(), args[1]?.ToString(), args[2]?.ToString(), args[3]?.ToString(), args[4]?.ToString());
                break;
            default:
                throw new ArgumentException($"Method with name {methodName} not known", nameof(methodName));
        }
    }

    /// <summary>
    /// RECOMMENDED WAY: Use reflection like a pro who actually likes C# and .NET.
    /// </summary>
    /// <param name="o"></param>
    /// <param name="methodName"></param>
    /// <param name="args"></param>
    private static void ExecuteMethod(object o, string methodName, params object[] args)
    {
        //beautiful, no? Will continue to work even for newly added methods.
        var type = o.GetType();
        //NonPublic to get the 'internal' methods
        var methodInfo = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        methodInfo.Invoke(o, args);
    }
}
相关问题