Могут ли параметры [] быть параметрами для лямбда-выражения?
Недавно я начал изучать лямбда-выражения, и на ум пришел вопрос. Скажем, у меня есть функция, которая требует неопределенного количества параметров. Я бы использовал ключевое слово params для моделирования этого переменного количества параметров.
Мой вопрос: могу ли я сделать что-то подобное с выражениями лямбда? Например:
Func<int[], int> foo = (params numbers[]) =>
{
int result;
foreach(int number in numbers)
{
result += numbers;
}
return result;
}
Если да, то существуют два подвопроса - есть ли "хороший" способ написать такое выражение, и я бы даже захотел написать такое выражение в какой-то момент?
Ответы
Ответ 1
Ну, вроде.
Во-первых, вместо использования Func<>
вам необходимо определить пользовательский делегат:
public delegate int ParamsFunc (params int[] numbers);
Затем вы можете написать следующую лямбду:
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<>
.
Ответ 2
Ближайшая вещь, которую, я думаю, вы можете получить, будет примерно такой:
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, ...}
Ответ 3
Здесь есть две вещи: общий делегат Func<int[], int>
на LHS и выражение лямбда на RHS. Первое невозможно, так как делегат Func<S, T>
объявлен как:
public delegate TResult Func<in T, out TResult>(T arg); //ie no params involved
Вам нужен ваш собственный делегат, который принимает вход params
, как показано в принятом ответе.
Последнее, о чем идет речь в вопросе, также невозможно в С#, , но по какой-то причине.
LHS выражения присваивания - это время компиляции (если только он dynamic
конечно, но снова компилятор знает об этом), а его RHS - это время выполнения (если, конечно, в случае const
s), Компилятор может сделать вывод о том, что напечатано на 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
, необязательный параметр, лямбда-выражения (или даже более ранний синтаксис delegate
) поддерживают только out/ref
.