Могу ли я игнорировать параметры делегата с лямбда-синтаксисом? - PullRequest
25 голосов
/ 03 февраля 2009

Мне любопытно, почему C # позволяет мне игнорировать параметры делегата в некоторых случаях, но не в других.

Например, это разрешено:

Action<int> action = delegate { Console.WriteLine("delegate"); };

но это не так:

Action<int> action = () => Console.WriteLine("lambda");

Есть ли способ инициализировать делегат и игнорировать параметры, используя лямбду? Я знаю, что могу добавить один параметр к лямбде и исправить предыдущую строку, но это скорее академический вопрос, относящийся к компилятору и почему или как это работает.

Ответы [ 7 ]

18 голосов
/ 03 февраля 2009

Я полагаю, что ваш первый пример на самом деле создает анонимную функцию, которая может принимать много разных подписей, тело которых является единственным оператором Console.WriteLine.... Поскольку он может совпадать с разными сигнатурами, это не вызывает проблем. Во втором примере сам лямбда-синтаксис определяет функцию, которая не принимает параметров с одинаковым телом. Очевидно, что последнее не соответствует определенному действию, поэтому вы получите ошибку.

C # Справочник по анонимным методам

Есть один случай, когда анонимный метод обеспечивает функциональность не найдена в лямбде выражения. Анонимные методы позволяют вам опустить список параметров, и это означает, что анонимный метод могут быть преобразованы в делегатов с Разнообразие подписей. Это не возможно с лямбда-выражениями.

8 голосов
/ 03 февраля 2009

Чтобы уточнить ответ tvanfosson; это поведение описано в спецификации языка C # 3.0 (§7.14):

Поведение лямбда-выражений и выражения-аноним-метод-это То же самое, за исключением следующих пунктов:

• разрешение выражений для анонимных методов список параметров, который нужно опустить полностью, уступая конвертируемости делегировать типы любого списка значений параметры.

• параметр разрешения лямбда-выражений типы, которые будут опущены и выведены тогда как выражения-аноним-метод-выражения требовать, чтобы типы параметров были прямо указано.

• Тело лямбда-выражения может быть выражением или блоком операторов в то время как тело Выражение anonymous-method-expression должно быть Блок выписки.

• Поскольку только лямбда-выражения могут есть выражение тела, нет Выражение anonymous-method-expression может быть успешно преобразован в тип дерева выражений (§4.6).

Я думаю:

Action<int> action = () => Console.WriteLine("lambda");

эквивалентно:

Action<int> action = delegate() { Console.WriteLine("delegate"); };

, который тоже не будет компилироваться. Как говорит Даниэль Плейстед, () прямо говорит, что нет никаких параметров.

Если существует эквивалент делегата {}, это может быть:

Action<int> action = => Console.WriteLine("lambda")

Что не очень красиво, и я подозреваю, что это подозрение не в духе лямбда-выражений.

5 голосов
/ 04 февраля 2009

Как говорили другие, нет, вы не можете пропустить объявление параметров в лямбду. Но для чистоты я предлагаю дать им имя, такое как _. Например

foo.Click += (_,__) => { ... }

Вы не игнорируете их как таковые, но указываете, что вам все равно, кто они, и не будете их использовать.

2 голосов
/ 03 февраля 2009

Синтаксис () => ... явно указывает, что лямбда не принимает параметров. Возможно, язык можно изменить так, чтобы () => действительно означало «Вывести для меня параметры этой лямбды» так же, как это делает синтаксис делегата, но это усложнило бы язык. При разработке новых языковых функций, вы начинаете с минус 100 , и я не думаю, что этот пройдёт тест.

Могут также быть более технические причины, по которым это будет трудно реализовать (что, вероятно, больше соответствует тому, о чем вы просили, но я сомневаюсь, что технические причины привели к принятию этого решения, если оно когда-либо придет).

0 голосов
/ 12 декабря 2013

На самом деле делегат {} не указывает никаких параметров и подходит для любой сигнатуры метода делегата - поэтому это разрешено в вашем первом построении.

Лямбда-выражение () => ...; В частности, указывается делегат без параметров, что противоречит подписи, требуемой для Action - делегата с одним параметром.

Вы можете использовать одну из следующих опций.

Если вам нужно, чтобы действие имело параметр, вы можете сделать это следующим образом («_» является допустимым символом для имени идентификатора).

Action<int> action = _ => Console.WriteLine("lambda");

Или вы можете использовать Действие без параметров следующим образом:

Action action = () => Console.WriteLine("lambda");

0 голосов
/ 03 апреля 2012

Как насчет этого?

Func<int> lamdapointer = () => TwoArgMethodThatReturnsInt(10,20); // the same method cannot be called with the delegate "NoArgmethodThatReturnsInt"


lamdapointer();

Delegate int NoArgmethodThatReturnsInt();
NoArgmethodThatReturnsInt del = NoArgmethodThatReturnsInt; // only this is possible with delegates


public int TwoArgMethodThatReturnsInt(int x,int y)
{
return x + y;
}

public int NoArgmethodThatReturnsInt()
{
return 20;
}
0 голосов
/ 03 февраля 2009

Я бы сказал, что для принудительного использования параметров лямбда-выражения.

Возьмите свой первый пример, как бы вы взаимодействовали с переданным значением, его локальное представление отсутствует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...