Почему С# не может использовать встроенные анонимные лямбды или делегаты?

Надеюсь, я правильно назвал название своего вопроса.

В С# я могу использовать lambdas (как делегаты) или старший синтаксис делегата для этого:

Func<string> fnHello = () => "hello";
Console.WriteLine(fnHello());

Func<string> fnHello2 = delegate()
{
    return "hello 2";
};
Console.WriteLine(fnHello2());

Итак, почему я не могу "встроить" лямбда или тело делегата и не улавливать его в именованной переменной (делая ее анонимной)?

// Inline anonymous lambda not allowed
Console.WriteLine(
    (() => "hello inline lambda")()
);

// Inline anonymous delegate not allowed
Console.WriteLine(
    (delegate() { return "hello inline delegate"; })()
);

Пример, который работает в javascript (только для сравнения):

alert(
    (function(){ return "hello inline anonymous function from javascript"; })()
);

Создает ожидаемое окно предупреждения.

UPDATE: Кажется, у вас может быть встроенная анонимная лямбда в С#, если вы настроили ее соответствующим образом, но количество() начинает расстраиваться.

// Inline anonymous lambda with appropriate cast IS allowed
Console.WriteLine(
    ((Func<string>)(() => "hello inline anonymous lambda"))()
);

Возможно, компилятор не может вывести sig анонимного делегата, чтобы узнать, какой Console.WriteLine() вы пытаетесь вызвать? Кто-нибудь знает, почему требуется конкретный отбор?

Ответ 1

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

var x = () => "some lambda";

Вам может понравиться

http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx

http://blogs.msdn.com/ericlippert/archive/2007/01/12/lambda-expressions-vs-anonymous-methods-part-three.aspx

Ответ 2

Кажется, что это сработает, если вы дадите ему тип cast:

String s = ((Func<String>) (() => "hello inline lambda"))();

Неужели это бесполезно? Не совсем. Возьмите ниже:

String s;
{
    Object o = MightBeNull();
    s = o == null ? "Default value" : o.ToString();
}

Теперь рассмотрим следующее:

String S = ((Func<Object,String>)(o => o == null ? "Default value" : o.ToString())
    )(MightBeNull());

Это немного уродливо, но оно компактно.

Ответ 3

Когда вы пишете Func<string> = ..., компилятор знает, что он должен создать объект типа Func<string>. Но когда вы пишете этот делегат inline, компилятор не знает объект, тип которого он должен создать.

Сказав вышеизложенное, можно сделать очевидный вывод: просто скажите компилятору тип явно!

Console.WriteLine( new Func<string>( () => "Hello" )() );

UPDATE

Хорошо, когда я писал ответ, вы обновили свой пост. Я считаю, что мой ответ выше уже отвечает на вопрос "зачем нужен этот конкретный тип". Повторить: поскольку компилятор не знает объект, тип которого создается.

Теперь немного уточнить, что "компилятор не может вывести часть анонимного делегата". Понимаете, это не похоже на JavaScript. В С# нет общего типа "функция" (или "метод" ). Каждый делегат должен иметь явно заданное имя подписи и типа. И когда вы создаете делегат, компилятор должен знать, какой тип.

Теперь я вижу, как вы можете подразумевать, что компилятор может просто построить тип делегата "на лету", как это происходит с анонимными типами объектов (aka new { a = 1, b = "xyz" }). Но подумайте об этом на мгновение: в любом случае, для такого делегата, вероятно, не будет пользы. Я имею в виду, вы не можете передать его другому методу, потому что этот метод должен сначала объявить типы его аргументов. И вы можете сделать из него событие, потому что, опять же, у вас должен быть именованный тип.

Что-то вроде этого...

Ответ 4

Вы можете использовать встроенные лямбда-выражения для методов, которые принимают параметр Delegate.

Однако есть небольшой catch - если параметр вводится в качестве базового типа Delegate, вам нужно явно указать его на определенный вывод делегата (например, Action); иначе компилятор будет жаловаться.

Похожие вопросы:
Анонимный метод в вызове Invoke
Анонимные методы и делегаты