Frage

Bei der Untersuchung von Delegaten in C# und .NET im Allgemeinen sind mir einige interessante Fakten aufgefallen:

Durch das Erstellen eines Delegaten in C# wird eine von abgeleitete Klasse erstellt MulticastDelegate mit einem Konstruktor:

.method public hidebysig specialname rtspecialname instance 
   void .ctor(object 'object', native int 'method') runtime managed { }

Das heißt, es erwartet die Instanz und einen Zeiger auf die Methode.Doch die Syntax zum Erstellen eines Delegaten in C# legt nahe, dass es einen Konstruktor gibt

new MyDelegate(int () target)

wo ich es erkennen kann int () als Funktionsinstanz (int *target() wäre ein Funktionszeiger in C++).Offensichtlich wählt der C#-Compiler die richtige Methode aus der durch den Funktionsnamen definierten Methodengruppe aus und erstellt den Delegaten.Die erste Frage wäre also: Woher wählt der C#-Compiler (oder Visual Studio, um genau zu sein) diese Konstruktorsignatur aus?Besondere Merkmale oder etwas, das einen Unterschied machen würde, sind mir nicht aufgefallen.Ist das eine Art Compiler-/Visualstudio-Magie?Wenn nicht, ist das T (args) target Konstruktion gültig in C#?Ich habe es nicht geschafft, etwas damit zu kompilieren, z.B.:

int () target = MyMethod;

ist ungültig, ebenso wie irgendetwas damit zu tun MyMetod, z.B.Berufung .ToString() darauf (naja, das macht durchaus Sinn, da es sich technisch gesehen um eine Methode handelt Gruppe, aber ich stelle mir vor, dass es möglich sein sollte, durch Casting explizit eine Methode auszuwählen, z. (int())MyFunction.Ist das alles also reine Compiler-Magie?Wenn man die Konstruktion durch den Reflektor betrachtet, offenbart sich noch eine weitere Syntax:

Func CS$1$0000 = new Func(null, (IntPtr) Foo);

Dies stimmt mit der disassemblierten Konstruktorsignatur überein, wird jedoch nicht kompiliert!

Ein letzter interessanter Hinweis ist, dass die Klassen Delegate Und MulticastDelegate habe noch weitere Konstruktorsätze:

.Method Family HideBysig SpecialName RtSpecialName Instance void .ctor (Klasse System.Type Ziel, String 'Methode') CIL Managed

Wo erfolgt der Übergang von einem Instanz- und Methodenzeiger zu einem Typ und einem String-Methodennamen?Lässt sich das dadurch erklären? runtime managed Schlüsselwörter in der Signatur des benutzerdefinierten Delegatenkonstruktors, d. h.Erledigt die Laufzeit hier ihren Job?

BEARBEITEN:Ok, ich denke, ich sollte das, was ich mit dieser Frage sagen wollte, umformulieren.Grundsätzlich behaupte ich, dass bei der Delegatenkonstruktion nicht nur C#-Compiler/CLR-Magie eine Rolle spielt, sondern auch einige Visual Studio Magie, da Intellisense beim Vorschlagen der Konstruktorargumente eine neue Syntax ausblendet und sogar eines davon verbirgt (z. B.Reflector verwendet diese Syntax und diesen Konstruktor übrigens nicht.

Ich habe mich gefragt, ob diese Behauptung wahr ist und ob die Syntax der Funktionsinstanz in C# eine tiefere Bedeutung hat oder es sich lediglich um ein konstantes Format handelt, das aus Gründen der Klarheit vom Visual Studio Magic-Teil implementiert wird (was Sinn macht, da es wie ungültiges C# aussieht)?Kurz gesagt: Wenn ich Intellisense implementieren würde, sollte ich dann etwas Magie für die Delegierten anwenden oder könnte ich den Vorschlag durch einen cleveren Mechanismus konstruieren?

ENDGÜLTIGE BEARBEITUNG:Der allgemeine Konsens ist also, dass es sich tatsächlich um VS-Magie handelt.Andere Beispiele (siehe Kommentar von Marc Gravell) für ein solches VS-Verhalten zu sehen, überzeugt mich davon, dass dies der Fall ist.

War es hilfreich?

Lösung

Das erste Argument wird aus der Objektreferenz (bzw null für statische Methoden);da gibt es keine Magie.

Sind die zweite Argument jedoch – es ist ein nicht verwalteter Zeiger (native int);Kurz gesagt, es gibt keine Alternative Direkte C#-Syntax, die diesen Konstruktor verwenden kann – er verwendet eine bestimmte IL-Anweisung (ldftn), um die Funktion aus Metadaten aufzulösen.Sie können es jedoch verwenden Delegate.CreateDelegate Delegierte durch Reflexion zu erstellen.Sie können auch IL emit (DynamicMethod usw.), aber es macht keinen Spaß.

Andere Tipps

Sie definieren zunächst den Delegaten (so kennt Visual Studio die Signatur der Zielmethode):

delegate void MyDelegate();

Dann konstruieren Sie Delegateninstanzen wie folgt:

MyDelegate method = new MyDelegate({method name});

// If this was the method you wanted to invoke:
void MethodToInvoke()
{
    // do something
}

MyDelegate method = new MyDelegate(MethodToInvoke);

C# wählt automatisch die Methode aus, die der Signatur des Delegaten entspricht.

Bearbeiten:Wenn Intellisense von Visual Studio Ihnen das anzeigt int () target Vorschlag: Es zeigt Ihnen die Signatur der C#-Methoden, die Sie verwenden können.Der C#-Compiler übersetzt die C#-Darstellung in IL.Die IL-Implementierung wird anders aussehen, da IL keine Sprache im C-Stil ist und der C#-Compiler syntaktischen Zucker bereitstellt, um die Implementierungsdetails zu abstrahieren.

Das ist nur eine Vermutung, also erschießen Sie mich nicht, wenn ich falsch liege, aber ich denke, Intellisense erhält die Signatur für die Zielmethode von Invoke Methode, die für den Delegaten definiert ist.Reflektor zeigt deutlich, dass die Invoke Methode auf System.Action<T> Ist:

[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);

Dies entspricht dem von Intellisense angebotenen Signaturvorschlag.Die Magie liegt darin, dass Intellisense beim Erkennen eines Delegatentyps auf den schaut Invoke -Methode und schlägt einen Konstruktor vor, der ein passendes Ziel annimmt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top