C# 使用指定的参数调用方法

C# 使用指定的参数调用方法,c#,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, st

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

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

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

并将其设置为:

methodArgs obj = new methodArgs();
obj.param1 = 10;
obj.param2 = "Hello World";
obj.param3 = 10.10;
obj.param4 = false;
然后像这样传递:

Run(obj);

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

可以使用反射动态获取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);
    }
}

我觉得这是最好的方法:

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

如果未找到argDic[a],将抛出异常,该参数始终需要在字典列表中匹配,然后可以调用该方法。此场景用于使用动态变量调用指定的方法。简单是什么意思?省略argDic[]部分,如Runa、b、c@shingo,如果反射是一个选项,则获取方法的元。每个参数的名称都要在字典列表中比较和查找。我仍然不明白,为什么要反思?参数名和字典键之间有关系吗?如果是,参数的值如何,它们是否有单独的用法?如果不是,则d无法传递给int d。代码运行argDic[a]、argDic[b]、argDic[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);
    }
}
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);