简体   繁体   English

使用Action和Func委托的可选和命名参数

[英]Using optional and named parameters with Action and Func delegates

Why it's not possible to do the following : 为什么不可能执行以下操作:

Func<int, int, int> sum = delegate(int x, int y = 20) { return x + y; };

Action<string, DateTime> print = 
    delegate(string message, DateTime datetime = DateTime.Now) 
    { 
        Console.WriteLine(message);
    };

sum(x: 20, y: 40);
print(datetime: DateTime.Now, message: "Hello");

case with only named parameters : 只有命名参数的情况:

Func<int, int, int> sum = delegate(int x, int y) { return x + y; };

Action<string, DateTime> print = 
    delegate(string message, DateTime datetime) 
    { 
        Console.WriteLine("{0} {1}", message, datetime);
    };

Console.WriteLine(sum(y: 20, x: 40));
print(datetime: DateTime.Now, message: "Hello");

case with only optional parameters: 只有可选参数的情况:

Func<int, int, int> sum = delegate(int x, int y = 20) { return x + y; };

Action<string , DateTime> print = 
    delegate(string message, DateTime datetime = DateTime.Now)
    { 
        Console.WriteLine("{0} {1}",message, datetime);
    };

Console.WriteLine(sum(40));
print("Hello");

As mentioned here - 如前所述这里 -

Optional parameters are an attribute of a method or delegate parameter. 可选参数是方法或委托参数的属性。 When you call a signature (method or delegate) that has a known optional parameter at compile-time, the compiler will insert the optional parameter value at the callsite. 在编译时调用具有已知可选参数的签名(方法或委托)时,编译器将在调用点处插入可选参数值。

The runtime is not aware of optional parameters, so you can't make a delegate that inserts an optional parameter when it's called. 运行时不知道可选参数,因此您无法在调用时插入可选参数。

So, to use that you have to extract out concrete implementation(custom delegate) which is known at compile time and will replace the parameters at call site with optional parameters and named parameters can be used as well. 因此,要使用它,您必须提取在编译时已知的具体实现(自定义委托),并将使用可选参数替换调用站点处的参数,并且也可以使用命名参数。

Declare custom delegate - 声明自定义委托 -

public delegate int FuncDelegate(int x, int y = 20);

Now you can use it in method body - 现在你可以在方法体中使用它 -

FuncDelegate sum = delegate(int x, int y) { return x + y; };
int result = sum (x : 20, y: 40 );
result = sum(20);

Also, only compile time constant can be used in default parameters list . 此外,只有compile time constant can be used in default parameters list But DateTime.Now is not a compile time constant so that cannot be used as well for specifying optional value to your parameter. DateTime.Now is not a compile time constant因此也不能用于为参数指定可选值。

So for Action part this will work - 因此,对于Action部分,这将有效 -

public delegate void ActionDelegate(string message,
                                    DateTime dateTime = default(DateTime));

Use delegate now here - 现在使用委托 -

ActionDelegate print =
                delegate(string message, DateTime dateTime)
                { Console.WriteLine(dateTime.ToString()); };
print(dateTime: DateTime.Now, message: "SomeThing");

You have an answer for the optional parameter part. 您有可选参数部分的答案。 Regarding the named parameter , its entirely possible to provide names for arguments, but just that x and y are not the parameter names for Action/Func generic delegates. 关于命名参数 ,它完全可以为参数提供名称,但只是xy不是Action/Func泛型委托的参数名称。 If you have a delegate declared like this: 如果你有一个像这样声明的委托:

delegate void D(int p);

//now
D x = a => { };

x(a: 1); //is illegal, since 'a' is not the name of the parameter but 'p'; so 
x(p: 1) //is legal

a really cant be that parameter name because a is just a part of the signature of the current method your delegate references to (ie the anonymous method). a真的不能成为参数名称,因为a只是委托引用的当前方法的签名的一部分(即匿名方法)。 It is not really part of the signature of the original delegate. 它并不是原始代表签名的一部分。 Think about this scenario: 想想这个场景:

D x = a => { };

//and somewhere else
x = b => { };

//and yet again
x = SomeMethod;

// now should it be x(a: 1) or x(b: 1) or x(parameterNameOfMethodSomeMethod: 1)?

Only p makes sense there. 只有p才有意义。

In the case of Action/Func they are declared like: Action/Func的情况下,它们被声明为:

public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

So you see the parameter naming right? 所以你看到参数命名正确吗? So in this case: 所以在这种情况下:

Func<int, int, int> sum = delegate(int x, int y) { return x + y; };
Action<string, DateTime> print =
    delegate(string message, DateTime datetime) { Console.WriteLine("{0} {1}", message, datetime); };

//and you should be calling them like:

Console.WriteLine(sum(arg1: 20, arg2: 40));
print(arg2: DateTime.Now, arg1: "Hello"); //note the order change here

Of course its meaningless in this scenario since you're not using any optional parameter. 当然,在这种情况下它没有任何意义,因为你没有使用任何可选参数。

C# 7 now allows for 'local functions' . C#7现在允许“本地功能” So instead of creating an Action<T> or Func<T> you can write a 'normal' method. 因此,您可以编写“正常”方法,而不是创建Action<T>Func<T> This means that normal rules about default parameters apply. 这意味着适用有关默认参数的常规规则。

So you can scope some piece of logic to be internal to a function without fighting with the delegate syntax. 因此,您可以将某些逻辑范围放在函数内部,而无需使用委托语法。

It also works like a closure so you have access to local variables from the 'parent' method. 它也像闭包一样工作,因此您可以从“父”方法访问局部变量。

I added a pointless throwAnException optional parameter below to Microsoft's example. 我在微软的例子中添加了一个无意义的throwAnException可选参数。

public static IEnumerable<char> AlphabetSubset3(char start, char end)
{
    if (start < 'a' || start > 'z')
        throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
    if (end < 'a' || end > 'z')
        throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter");

    if (end <= start)
        throw new ArgumentException($"{nameof(end)} must be greater than {nameof(start)}");

    return alphabetSubsetImplementation();

    IEnumerable<char> alphabetSubsetImplementation(bool throwAnException = false)
    {
        if (throwAnException) { throw Exception("You asked me to do this"); }

        for (var c = start; c < end; c++)
            yield return c;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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