我最近开始探索lambda表达式,我想到了一个问题。 假设我有一个函数,需要不确定数量的参数。 我会使用 params 关键字来对可变数量的参数进行建模。
我的问题:我可以对 Lambda 表达式做类似的事情吗? 例如:
Func<int[], int> foo = (params numbers[]) =>
{
int result;
foreach(int number in numbers)
{
result += numbers;
}
return result;
}
如果是这样,则会出现两个子问题 - 是否有一种"好"的方式来编写这样的表达式,我什至想在某个时候编写这样的表达式吗?
嗯,有点。首先,您需要定义一个自定义委托,而不是使用 Func<>
:
public delegate int ParamsFunc (params int[] numbers);
然后,您可以编写以下 lambda:
ParamsFunc sum = p => p.Sum();
并使用可变数量的参数调用它:
Console.WriteLine(sum(1, 2, 3));
Console.WriteLine(sum(1, 2, 3, 4));
Console.WriteLine(sum(1, 2, 3, 4, 5));
但说实话,坚持使用内置Func<>
代表确实要简单得多。
我认为你能得到的最接近的东西是这样的:
Func<int[], int> foo = numbers[] =>
{
// logic...
}
var result = foo(Params.Get(1, 5, 4, 4, 36, 321, 21, 2, 0, -4));
并具有:
public static class Params
{
public static T[] Get(params T[] arr)
{
return arr;
}
}
但我看不出这如何击败一个简单的new[] {1, 5, 4, 4, ...}
这里有两件事,LHS上的Func<int[], int>
泛型委托和RHS上的lambda表达式。前者是不可能的,因为Func<S, T>
委托的声明如下:
public delegate TResult Func<in T, out TResult>(T arg); //ie no params involved
您需要自己的接受params
输入的委托,如接受的答案所示。
后者是问题标题的内容,在 C# 中也是不可能的,但这是有原因的。
赋值表达式的 LHS 是一个编译时的东西(当然,除非它是dynamic
的,但编译器再次知道它),它的 RHS 是一个运行时的东西(当然,除非在 const
的情况下)。编译器可以推断在 LHS 上键入的内容,但它仅在运行时(即代码运行时)获取 RHS 上的值。当您键入以下内容时:
Func<int[], int> foo = ....
foo
总是被认为是Func<int[], int>
。如果编译器必须破译 RHS,它将增加很多复杂性。例如,如果您正在尝试的是可能的,请考虑以下场景:
Func<int[], int> foo = (params int[] numbers) =>
{
int result;
foreach(int number in numbers)
{
result += numbers;
}
return result;
};
//and later at some other place
foo = (int[] numbers) => 0;
//how would you call 'foo' now?
相反,当你编写自己的接受params
委托时,你直接告诉编译器(即从LHS知道)。
在命名方法的参数支持的三个功能中,即out/ref
、params
、可选参数、lambda 表达式(甚至更早的delegate
语法)仅支持out/ref
。