Sind Delegates leichter als Klassen?

8

Ich habe versucht, eine C # erstellte ausführbare Datei zu demontieren, aber ich konnte nicht zu einem Ergebnis kommen. Was ich gerne wissen würde ist, dass, wenn für die CLR c # 's Delegierte wirklich spezielle Entitäten oder nur ein Compiler Zucker sind?

Ich frage das, weil ich eine Sprache implementiere, die nach C # kompiliert, und es wäre viel interessanter für mich, anonyme Funktionen als Klassen als als Delegierte zu kompilieren. Aber ich möchte kein Design verwenden, das ich später bereuen werde, da sie vielleicht schwerer im Gedächtnis sind (ich denke an Java's PermGen, um meine Fragen zu begründen. Obwohl ich weiß, dass es so etwas für die CLR nicht gibt) / p>

Danke!

- Bearbeiten

Um ein wenig klarer zu sein, würde ich gerne wissen, ob es (und was) die Unterschiede zwischen:

gibt %Vor%

und zum Beispiel

%Vor%

- Bearbeiten

Ich denke, dass es einen großen Unterschied geben könnte zwischen:

%Vor%

und

%Vor%

Ich habe irgendwo gelesen, dass die Syntax Func<int, int, int> add = Program.add; nur ein Zucker für Func<int, int, int> add = delegate(int a, int b) { return Program.add; }; ist. Aber ich weiß wirklich nicht, ob das wirklich stimmt. Ich konnte auch sehen, dass der C # -Compiler alle diese Instanzen bereits speichert, so dass sie nur einmal erstellt werden. Ich könnte das gleiche mit meinem Compiler tun, though.

    
Waneck 19.02.2011, 17:36
quelle

5 Antworten

7

Ich bin überrascht, dass Sie nicht zu einem Ergebnis kommen konnten, indem Sie eine ausführbare Datei zerlegen. Werfen wir einen Blick auf etwas wirklich einfaches:

%Vor%

Wenn wir das zerlegen, bekommen wir

%Vor%

Wie Sie sehen können, wird RealVoidIntDelegate "nur" eine andere Klasse. Sie haben es Invoke anstelle von Call genannt, und sie haben keine Schnittstelle benutzt, aber es gibt keine speziellen Anweisungen, es ist die gleiche Grundidee.

Um ein wenig über die Idee des "Lightweightness" zu sprechen, sind Delegaten nicht leichter als Klassen, weil ein gegebener Delegat eine Klasse ist. Insbesondere im Falle der Funktions-Literal-Syntax können sie wirklich nicht viel leichter sein. Jedoch für den "Aufruf dieser Methode für dieses Objekt mit diesen Argumenten" wird der Fall, der einen gegebenen Delegaten aufruft und erstellt, wahrscheinlich ein geringeres Gewicht haben als ein selbst entwickelter Delegierter, wenn er sich auf C # kompiliert.

    
Logan Capaldo 19.02.2011, 18:04
quelle
3

Delegierte sind Klassen. Der .NET-Compiler erstellt für jeden Delegaten einen Typ, und der Code muss einen Delegaten instanziieren.

In jedem Fall ist der Unterschied in der Leistung vernachlässigbar, es sei denn, Sie schreiben eine der sehr seltenen Anwendungen, bei denen jede Nanosekunde wichtig ist.

    
Puneet 19.02.2011 18:03
quelle
3

Hier gibt es kein großes Geheimnis. Channing Jon Skeet ...

Wenn Sie sich 6.5.3 der C # -Spezifikation ansehen, werden Sie einige sehen Beispiele, wie anonyme Delegaten vom Compiler behandelt werden. Eine kurze Zusammenfassung:

IF Die anonyme Methode erfasst keine äußeren Variablen, und THEN kann als statische Methode für den einschließenden Typ erstellt werden.

IF Die anonyme Methode verweist auf Elemente des umschließenden Typs, z. this.x
THEN kann als Instanzmethode für den umschließenden Typ erstellt werden.

IF Die anonyme Methode erfasst eine lokale Variable, und THEN kann als geschachtelter Type innerhalb des umschließenden Typs mit Instanzvariablen erstellt werden, die dem erfassten entsprechen Variablen und eine Instanzmethode, die dem Delegattyp entspricht.

Das letzte Beispiel ist komplizierter und es ist einfacher, sich den Code anzusehen. Schauen Sie selbst und ich denke, es wird alle Rätselraten beseitigen.

    
Josh 19.02.2011 18:13
quelle
1

Es scheint sehr wenig Unterschied zwischen den beiden zu geben, das obere Snippet wird effektiv zu etwas kompiliert, das fast identisch mit dem ist, was Sie im unteren Snippet haben.

    
Iridium 19.02.2011 18:01
quelle
1

Abgesehen von Meta-Daten gibt es wirklich nicht so etwas wie eine Klasse, sobald alles fertig ist JIT kompiliert. Die Laufzeitdarstellung eines Objekts ist ein Byte-Array genug, um alle Felder der Klasse und zu speichern Es sind Basisklassen und ein Objektkopf, der a speichert Hash-Code, eine numerische Typkennung und ein Zeiger auf eine freigegebene V-Tabelle, die Adressen von virtuellen Funktionsüberschreibungen enthält.

Ein Delegat ist ein Objekt, dessen Klasse von System.Delegate abgeleitet ist. Es speichert ein Array von Objekt- und Funktionszeigerpaaren.

Eine anonyme Funktion ist eine Funktion, die keinen Namen hat. Sie sind es aber auch normalerweise mit einem Objekt verknüpft, das als Closure bezeichnet wird und alle Parameter und Locals enthält, die in der containing-Methode definiert sind, die den "anonymen Delegaten" erstellt hat, der auf die anonyme Funktion verweist. (Tatsächlich enthält es normalerweise nur die Variablen, auf die tatsächlich zugegriffen wird.)

In jedem Fall erlaubt das Verschieben der Stapelvariablen in den Heap dem anonymen Delegaten, seinen definierenden Stapelrahmen zu leben.

Der einfachste Weg, um eine anonyme Funktion mit der Closure zu verknüpfen, ist, sie zu einer Methode der vom Compiler generierten Closure-Klasse zu machen.

Wenn Sie also lexikalische Closures haben, müssen Sie (zumindest in einigen Fällen) eine Klasse verwenden, um anonyme Funktionen zu implementieren.

Wenn Sie keine lexikalischen Schließungen haben, können Sie einfach die "anonyme Funktion" als " reguläre Funktion mit einem vom Compiler erzeugten Namen, neben der Methode, die sie deklariert hat. Dies ist auch eine nützliche Optimierung in Fällen, in denen die Sprache lexikalische Schließungen unterstützt, aber eine wird nicht benötigt.

Im Allgemeinen sind anonyme Funktionen ohne Closure-Unterstützung nicht sinnvoll, daher würde ich sie nicht ohne Unterstützung für Schließungen in Ihre Sprache aufnehmen.

    
Scott Wisniewski 19.02.2011 18:38
quelle

Tags und Links