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