Для розуміння такої поведінки потрібно знати дві речі.
- Усі делегати походять від
System.Delegate
, але різні делегати мають різні типи, і тому їх не можна призначати один одному.
- Мова C # забезпечує спеціальну обробку для присвоєння методу або лямбда делегату .
Оскільки різні делегати мають різні типи, це означає, що ви не можете призначити делегата одного типу іншому.
Наприклад, наведено:
delegate void test1(int i);
delegate void test2(int i);
Тоді:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
Перший рядок складається з ОК, оскільки він використовує спеціальну обробку для присвоєння лямбда або методу делегату.
Насправді цей рядок ефективно переписаний таким чином компілятором:
test1 a = new test1(Console.WriteLine);
Другий рядок вище не компілюється, оскільки він намагається призначити екземпляр одного типу іншому несумісному типу.
Наскільки на типи йти, не сумісні між присвоювання test1
і test2
тому , що вони мають різні типи.
Якщо це допомагає подумати над цим, врахуйте цю ієрархію класів:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
Наступний код НЕ буде компілюватись, хоча Test1
і Test2
походить з одного базового класу:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
Це пояснює, чому ви не можете призначити один тип делегата іншому. Це просто звичайна мова C #.
Однак найважливіше - зрозуміти, чому вам дозволяється призначити метод або лямбда сумісному делегату. Як зазначалося вище, це є частиною підтримки мови C # для делегатів.
Отже, нарешті, щоб відповісти на ваше запитання:
Під час використання Invoke()
ви призначаєте виклику METHOD делегату, використовуючи спеціальну обробку мови C # для призначення методів або лямбдатів делегату, а не намагатися призначити несумісний тип - значить, він компілює OK.
Щоб бути абсолютно зрозумілим, код, який складається у вашому ОП:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Насправді концептуально перетворюється на щось на кшталт:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
Тоді як код, який не працює, намагається призначити між двома несумісними типами:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}