Я не понимаю этот случай:
public delegate int test(int i);
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
public test Fail()
{
Func<int, int> f = x => x;
return f; // <- code doesn't compile
}
Почему компиляция в порядке, когда я использую Invoke
метод, и не в порядке, когда я возвращаюсь csharp Func<int,int>
напрямую?
delegate void test1(int i);
иdelegate void test2(int i);
Ответы:
Есть две вещи, которые вы должны знать, чтобы понять это поведение.
System.Delegate
, но разные делегаты имеют разные типы и поэтому не могут быть назначены друг другу.Поскольку разные делегаты имеют разные типы, это означает, что вы не можете назначить делегата одного типа другому.
Например, учитывая:
Затем:
Первая строка выше компилирует OK, потому что она использует специальную обработку для назначения лямбда-функции или метода делегату.
Фактически, эта строка эффективно переписывается компилятором следующим образом:
Вторая строка выше не компилируется, потому что она пытается присвоить экземпляр одного типа другому несовместимому типу.
Что касается типов, не существует совместимого назначения между
test1
иtest2
потому, что они разных типов.Если это помогает думать об этом, рассмотрите эту иерархию классов:
Следующий код не будет компилироваться, хотя
Test1
иTest2
вытекает из того же базового класса:Это объясняет, почему вы не можете назначить один тип делегата другому. Это просто нормальный язык C #.
Однако важно понять, почему вы можете назначить метод или лямбду совместимому делегату. Как отмечалось выше, это является частью поддержки языка C # для делегатов.
Итак, наконец, чтобы ответить на ваш вопрос:
При использовании
Invoke()
вы назначаете делегату вызов METHOD, используя специальную обработку языка C # для назначения методов или лямбда-выражений делегату, а не пытаетесь назначить несовместимый тип - следовательно, он компилируется OK.Чтобы быть полностью понятным, код, который компилируется в вашем OP:
Фактически конвертируется концептуально в нечто вроде:
Принимая во внимание, что код ошибки пытается назначить между двумя несовместимыми типами:
источник
Во втором случае
f
имеет типFunc<int, int>
, но говорят, что метод возвращает atest
. Это несвязанные (делегированные) типы, которые необратимы друг для друга, поэтому возникает ошибка компилятора. Вы можете перейти к этому разделу спецификации языка и выполнить поиск «делегат». Вы не найдете упоминаний о преобразованиях между делегатами с одинаковыми подписями.В первом случае, однако,
f.Invoke
это выражение группы методов , которое на самом деле не имеет типа. Компилятор C # преобразует выражения группы методов в конкретные типы делегатов в соответствии с контекстом посредством преобразования группы методов .(Цитирую 5-ую пулю здесь , выделение мое)
В этом случае он преобразуется в
test
тип делегата.Другими словами,
return f
не работает, потому чтоf
уже имеет тип, ноf.Invoke
еще не имеет тип.источник
Проблема здесь: Тип совместимости:
Ниже приведено определение делегата Func из MSDN Sources:
public delegate TResult Func<in T, out TResult>(T arg);
Если вы видите, что нет прямой связи между Func, упомянутым выше, и вашим определенным делегатом:
public delegate int test(int i);
Делегаты сравниваются с использованием сигнатуры, то есть входных параметров и результата вывода, в конечном итоге делегат является указателем на функцию, а две функции можно сравнивать только через подпись. Во время выполнения метод, вызываемый через Func, присваивается
Test
делегату, поскольку Signature одинакова и работает без проблем. Это назначение указателя функции, гдеTest
делегат теперь будет вызывать метод, указанный делегатом Func.Между Func и тестовым делегатом нет совместимости типов / назначений, Func не может заполнить как часть правил системы типов. Даже тогда, когда его результат может быть назначен и заполнен,
test delegate
как в первом случае.источник