[英]C# how do I pass optional parameters as a collection?
假设我有第 3 方MethodA(type1 paramName1 = null, type2 paramName2 = null,...., nonNullAbleSuchAsInt paramName10 = 123)
。
我想通过使用用户提供的数据调用相同的 MethodA 来执行以下操作。 用户可以给我 paramName2 和 paramName4 的数据,或者其他一些排列,例如 [paramName2, paramName3, paramName5, paramName7] 等。
if(user gives me data for paramName2 and nothing else)
{
MethodA(paramName2=userData2)
}
else if(user give me data for paramName2, paramName3, and nothing else)
{
MethodA(paramName2=userData2, paramName3=userData3)
}
else if(user give me data for paramName2, paramName4, and nothing else)
{
MethodA(paramName2=userData2, paramName4=userData4)
}
else if(user give me data for paramName2, paramName3, paramName4, and nothing else)
{
MethodA(paramName2=userData2, paramName3=userData3, paramName4=userData4)
}
... repeat for all permutations.
但是,这是很多重复的代码。
我想做以下事情。 我该怎么做?
MagicStorage<MethodA_Declaration> magicArgs = new MagicStorage<MethodA_Declaration>();
if(user gives me data for paramName1)
{
magicArgs.Add(paramName1, userData1);
}
if(user gives me data for paramName2)
{
magicArgs.Add(paramName2, userData2);
}
... repeat
if(user gives me data for paramName10)
{
magicArgs.Add(paramName10, userData10);
}
MethodA(magicArgs);
如果我犯了一个错误,比如userData10
is not the same type required by paramName10
,我会得到编辑器和编译器错误。
这可能吗? 我不想对用户输入数据的所有排列进行方法调用。 将有太多代码需要管理。
给定
MethodA(type1 paramName1 = null, type2 paramName2 = null, int paramName10 = 132).
用法
public class data
{
public type1 ParamName1 {get;set;}
public type2 paramName2 {get;set;}
// initalize with what ever default the method takes as optional
public int paramName10 {get;set;} = 123;
}
...
// pass in all paramaters, dont both about ifs
// we can do this, because you have already figured out the defaults
// from the signature
MethodA(data.ParamName1, data.paramName2, data.paramName10);
一种方法是使用反射来调用具有有序参数数组的方法,其中尽可能使用用户指定的值,在未指定值的情况下使用Type.Missing
:
public static object InvokeWithOrderedParameters(object instance, string methodName,
IDictionary<string, object> namedParameters)
{
// Get the method to invoke
var method = instance.GetType().GetMethod(methodName);
// Get an array of ordered parameter values based on the specified named
// parameters, with a default value of "Type.Missing" for any missing names
var orderedParams = method.GetParameters().Select(param =>
{
object value;
// Set the value from our dictionary, or if that fails use "Type.Missing"
if (!namedParameters.TryGetValue(param.Name, out value))
{
value = Type.Missing;
}
return value;
}).ToArray();
// Invoke the method with the ordered parameters and return the value
return method.Invoke(instance, orderedParams);
}
使用此方法,我们可以传递我们类型的实例、要调用的方法的名称以及命名参数及其值的Dictionary<string, object>
,它会返回调用该方法的结果,该方法的参数是我们指定。
例如,这里有一个方法,它的所有参数都有默认值:
public class ThirdParty
{
public string MethodA(string arg1 = "defaultArg1", string arg2 = "defaultArg2",
string arg3 = "defaultArg3")
{
return $"{arg1}, {arg2}, {arg3}";
}
}
我们可以使用我们的反射方法来调用它,并使用尽可能多的命名参数。 下面我只是给第二个参数一个值:
public static void Main(string[] args)
{
var namedParameters = new Dictionary<string, object>
{
{"arg2", "custom Arg 2 value"}
};
var instance = new ThirdParty();
var result = InvokeWithOrderedParameters(instance, "MethodA", namedParameters);
Console.WriteLine(result.ToString());
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
正如你所看到的,我们指定的值被传递了,并且在我们没有指定任何东西的地方使用了默认值:
您可以使用模式匹配的开关支持使其更具可读性。
当然,您可以用字典和循环替换任何开关,只要该值具有 function 代表的位置。 当然,在这种情况下,Key 可能也需要有一个委托。
那些会使代码更具可读性,但不能避免编写工作。
除此之外,只有将 function 调用的分辨率从编译时移到运行时。 一步我不是朋友,因此经验很少。
你可以有类似的东西
int param1 = default(int);
double param2 = default(double);
MyClass param3 = default(MyClass);
....
int param10 = 123;
ReadUserData(out param1, out param2, out param3, ..., out param10)
然后调用MethodA
:
MethodA(param1, param2, param3, ..., param10)
注意:从 C# 7.0 开始(我认为)当使用out
参数时,有一种糖可以让您使用方法调用声明变量(因此您不必一一声明它们),例如,对ReadUserData
的调用可以这样做:
ReadUserData(out int param1, out double param2, out MyClass param3, ..., out int param10)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.