Há duas coisas que você precisa saber para entender esse comportamento.
- Todos os delegados derivam de
System.Delegate
, mas delegados diferentes têm tipos diferentes e, portanto, não podem ser atribuídos um ao outro.
- A linguagem C # fornece tratamento especial para atribuir um método ou lambda a um delegado .
Como delegados diferentes têm tipos diferentes, isso significa que você não pode atribuir um delegado de um tipo para outro.
Por exemplo, dado:
delegate void test1(int i);
delegate void test2(int i);
Então:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
A primeira linha acima compila OK porque está usando o tratamento especial para atribuir um lambda ou um método a um delegado.
De fato, essa linha é efetivamente reescrita assim pelo compilador:
test1 a = new test1(Console.WriteLine);
A segunda linha acima não é compilada porque está tentando atribuir uma instância de um tipo a outro tipo incompatível.
No que diz respeito aos tipos, não há atribuição compatível entre test1
e test2
porque são tipos diferentes.
Se ajudar a pensar sobre isso, considere esta hierarquia de classes:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
O código a seguir não irá compilar, embora Test1
e Test2
derivam da mesma classe base:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
Isso explica por que você não pode atribuir um tipo de delegado a outro. Essa é apenas a linguagem C # normal.
No entanto, o importante é entender por que você pode atribuir um método ou lambda a um representante compatível. Como observado acima, isso faz parte do suporte ao idioma C # para delegados.
Então, finalmente, para responder à sua pergunta:
Quando você usa, Invoke()
está atribuindo uma chamada de MÉTODO ao delegado, usando a manipulação de linguagem C # especial para atribuir métodos ou lambdas a um delegado, em vez de tentar atribuir um tipo incompatível - portanto, ele compila OK.
Para ser completamente claro, o código que é compilado no seu OP:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Na verdade, é convertido conceitualmente para algo como:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
Enquanto o código com falha está tentando atribuir entre dois tipos incompatíveis:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}