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

时间:2013-11-03 10:11:50

标签: c# delegates

为什么不可能执行以下操作:

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

只有命名参数的情况:

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

仅包含可选参数的情况:

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

3 个答案:

答案 0 :(得分:7)

如上所述here -

  

可选参数是方法或委托的属性   参数。当您调用具有。的签名(方法或委托)时   在编译时已知可选参数,编译器将插入   呼叫现场的可选参数值。

     

运行时不知道可选参数,因此您无法创建   委托在调用时插入可选参数。

因此,要使用它,您必须提取在编译时已知的具体实现(自定义委托),并将使用可选参数和命名参数替换调用站点处的参数。

声明自定义委托 -

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

现在您可以在方法体中使用它 -

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

此外,仅compile time constant can be used in default parameters list。 但是DateTime.Now is not a compile time constant因此也不能用于为参数指定可选值。

因此,对于Action部分,这将起作用 -

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

现在使用委托 -

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

答案 1 :(得分:2)

您有可选参数部分的答案。关于命名参数,它完全可以为参数提供名称,但xy不是Action/Func泛型委托的参数名称。如果你有一个像这样声明的委托:

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实际上不能成为参数名称,因为a只是委托引用的当前方法的签名的一部分(即匿名方法)。它并不是原始代表签名的一部分。想想这个场景:

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

只有p才有意义。

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

所以你看到参数命名正确吗?所以在这种情况下:

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

当然,在这种情况下它没有任何意义,因为你没有使用任何可选参数。

答案 2 :(得分:0)

C#7现在允许'local functions'。因此,您可以编写“正常”方法来代替创建#include<iostream> using namespace std; int main() { string user_input; double price; do { cin >> price; int multiple = price * 100; if (user_input == "q") { break; } else if (multiple % 5 == 0) { cout << "This is a multiple of 0.05" << endl; return 1; } else { cout << "No multiple" << endl; } } while (1 || user_input != "q"); system("pause"); } Action<T>。这意味着适用默认参数的一般规则。

因此,您可以在不使用委托语法的情况下将某些逻辑范围限定在函数内部。

它也像闭包一样工作,因此您可以通过'parent'方法访问局部变量。

我在下面的Microsoft示例中添加了一个毫无意义的Func<T>可选参数。

throwAnException