Ci sono due cose che devi sapere per capire questo comportamento.
- Tutti i delegati derivano
System.Delegate
, ma delegati diversi hanno tipi diversi e pertanto non possono essere assegnati l'uno all'altro.
- Il linguaggio C # fornisce una gestione speciale per l'assegnazione di un metodo o lambda a un delegato .
Poiché delegati diversi hanno tipi diversi, ciò significa che non è possibile assegnare un delegato di un tipo a un altro.
Ad esempio, dato:
delegate void test1(int i);
delegate void test2(int i);
Poi:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
La prima riga sopra viene compilata OK perché utilizza la gestione speciale per assegnare un lambda o un metodo a un delegato.
In effetti, questa riga viene effettivamente riscritta in questo modo dal compilatore:
test1 a = new test1(Console.WriteLine);
La seconda riga sopra non viene compilata perché sta tentando di assegnare un'istanza di un tipo a un altro tipo incompatibile.
Per quanto riguarda i tipi, non esiste un'assegnazione compatibile tra test1
e test2
perché sono tipi diversi.
Se aiuta a pensarci, considera questa gerarchia di classi:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
Il seguente codice NON verrà compilato, anche se Test1
e Test2
deriverà dalla stessa classe di base:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
Questo spiega perché non è possibile assegnare un tipo delegato a un altro. Questo è solo il normale linguaggio C #.
Tuttavia, la cosa cruciale è capire perché ti è permesso assegnare un metodo o lambda a un delegato compatibile. Come notato sopra, questo fa parte del supporto del linguaggio C # per i delegati.
Quindi finalmente per rispondere alla tua domanda:
Quando si utilizza Invoke()
si assegna una chiamata METHOD al delegato utilizzando la speciale gestione del linguaggio C # per assegnare metodi o lambdas a un delegato anziché tentare di assegnare un tipo incompatibile, quindi viene compilato OK.
Per essere completamente chiari, il codice che compila nel tuo OP:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
In realtà viene convertito concettualmente in qualcosa del tipo:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
Considerando che il codice in errore sta tentando di assegnare tra due tipi incompatibili:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}