Ich verstehe diesen Fall nicht:
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
}
Warum ist die Kompilierung in Ordnung, wenn ich die Invoke
Methode verwende, und nicht in Ordnung, wenn ich csharp Func<int,int>
direkt zurückkehre?
delegate void test1(int i);
und verwendendelegate void test2(int i);
Antworten:
Es gibt zwei Dinge, die Sie wissen müssen, um dieses Verhalten zu verstehen.
System.Delegate
, aber unterschiedliche Delegierte haben unterschiedliche Typen und können daher nicht einander zugewiesen werden.Da verschiedene Delegaten unterschiedliche Typen haben, können Sie einen Delegaten eines Typs keinem anderen zuweisen.
Zum Beispiel gegeben:
Dann:
In der ersten Zeile oben wird OK kompiliert, da die spezielle Behandlung zum Zuweisen eines Lambda oder einer Methode zu einem Delegaten verwendet wird.
Tatsächlich wird diese Zeile vom Compiler effektiv wie folgt umgeschrieben:
Die zweite Zeile oben wird nicht kompiliert, da versucht wird, eine Instanz eines Typs einem anderen inkompatiblen Typ zuzuweisen.
Was die Typen betrifft, gibt es keine kompatible Zuordnung zwischen
test1
und,test2
da es sich um verschiedene Typen handelt.Wenn es hilfreich ist, darüber nachzudenken, berücksichtigen Sie diese Klassenhierarchie:
Der folgende Code wird nicht kompiliert, obwohl
Test1
undTest2
stammt aus der gleichen Basisklasse:Dies erklärt, warum Sie einen Delegatentyp keinem anderen zuweisen können. Das ist nur die normale C # -Sprache.
Entscheidend ist jedoch, zu verstehen, warum Sie einem kompatiblen Delegaten eine Methode oder ein Lambda zuweisen dürfen. Wie oben erwähnt, ist dies Teil der C # -Sprachenunterstützung für Delegierte.
Also endlich um deine Frage zu beantworten:
Wenn Sie verwenden
Invoke()
, weisen Sie dem Delegaten einen METHOD-Aufruf zu, indem Sie die spezielle C # -Sprachenbehandlung verwenden, um einem Delegaten Methoden oder Lambdas zuzuweisen, anstatt zu versuchen, einen inkompatiblen Typ zuzuweisen. Daher wird OK kompiliert.Um ganz klar zu sein, der Code, der in Ihrem OP kompiliert wird:
Wird tatsächlich konzeptionell in etwas umgewandelt wie:
Während der fehlerhafte Code versucht, zwischen zwei inkompatiblen Typen zuzuweisen:
quelle
Im zweiten Fall
f
ist vom TypFunc<int, int>
, aber die Methode soll a zurückgebentest
. Dies sind nicht verwandte (delegierte) Typen, die nicht miteinander konvertierbar sind, sodass ein Compilerfehler auftritt. Sie können zu diesem Abschnitt der Sprachspezifikation gehen und nach "Delegat" suchen. Conversions zwischen Delegaten mit denselben Signaturen werden nicht erwähnt.Im ersten Fall handelt es sich jedoch
f.Invoke
um einen Methodengruppenausdruck , der eigentlich keinen Typ hat. Der C # -Compiler konvertiert Methodengruppenausdrücke je nach Kontext durch eine Methodengruppenkonvertierung in bestimmte Delegatentypen .(Zitiert die 5. Kugel hier , Hervorhebung von mir)
In diesem Fall wird es in den
test
Delegattyp konvertiert .Mit anderen Worten,
return f
funktioniert nicht, weil esf
bereits einen Typ gibt, aberf.Invoke
noch keinen Typ.quelle
Hier geht es um die Typkompatibilität:
Es folgt die Definition des Func- Delegaten aus MSDN-Quellen:
public delegate TResult Func<in T, out TResult>(T arg);
Wenn Sie sehen, dass es keine direkte Beziehung zwischen der oben genannten Funktion und Ihrem definierten Delegierten gibt:
public delegate int test(int i);
Delegaten werden mit der Signatur verglichen, bei der es sich um Eingabeparameter und Ausgabeergebnisse handelt. Letztendlich ist ein Delegat ein Funktionszeiger, und zwei Funktionen können nur über die Signatur verglichen werden. Zur Laufzeit wird die über Func aufgerufene Methode dem
Test
Delegaten zugewiesen , da die Signatur identisch ist und nahtlos funktioniert. Es handelt sich um eine Funktionszeigerzuweisung, bei der derTest
Delegat nun die vom Func-Delegaten angegebene Methode aufruftZwischen Func und dem Testdelegierten besteht keine Typ- / Zuweisungskompatibilität. Func kann nicht als Teil der Typsystemregeln ausgefüllt werden. Auch wenn das Ergebnis
test delegate
wie im ersten Fall zugewiesen und ausgefüllt werden kann.quelle