繁体   English   中英

C# 如何将可选参数作为集合传递?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM