8 Stimmen

Ist es Delegates leichter als Klassen?

Ich habe versucht, ein mit C# erstellbares ausführbares Programm zu zerlegen, kam aber zu keinem Ergebnis. Was ich gerne wissen würde, ist, ob für das CLR c#'s Delegaten wirklich spezielle Entitäten oder nur Zucker für den Compiler sind?

Ich frage deshalb, weil ich eine Sprache implementiere, die nach C# compiliert wird, und es für mich viel interessanter wäre, anonyme Funktionen als Klassen zu kompilieren, anstatt als Delegaten. Aber ich möchte kein Design verwenden, das ich später bereuen werde, da sie möglicherweise mehr Speicher verbrauchen (ich denke an Javas PermGen, um meine Fragestellung zu begründen. Obwohl ich weiß, dass es so etwas nicht für das CLR gibt).

Danke!

-- Bearbeiten

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

void Main()
{
    Func add = delegate(int a, int b) {return a + b;};
}

und zum Beispiel

class AnonFuncion__1219023 : Fun3
{
    public override int invoke(int a, int b)
    {
        return a + b;
    }
}

-- Bearbeiten

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

class Program
{
    static int add(int a, int b)
    {
        return a + b;
    }

    static void Main()
    {
        Func add = Program.add;
    }
}

und

class Function__432892 : Fun3
{
    public override int invoke(int a, int b)
    {
        return Program.add(a, b);
    }
}

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

3voto

Puneet Punkte 1014

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

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

3voto

Josh Punkte 44274

Hier ist kein großes Geheimnis. Kanalisierung von Jon Skeet...

Wenn Sie sich 6.5.3 des C#-Spezifikation anschauen, finden Sie mehrere Beispiele, wie anonyme Delegaten vom Compiler behandelt werden. Eine kurze Zusammenfassung:

WENN die anonyme Methode keine äußeren Variablen erfasst,
DANN kann sie als statische Methode im umschließenden Typ erstellt werden.

WENN die anonyme Methode auf Member des umschließenden Typs verweist, z.B. this.x
DANN kann sie als Instanzmethode im umschließenden Typ erstellt werden.

WENN die anonyme Methode eine lokale Variable erfasst,
DANN kann sie als verschachtelter Typ im umschließenden Typ erstellt werden, mit Instanzvariablen, die den erfassten Variablen entsprechen, und einer Instanzmethode, die dem Delegattyp entspricht.

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

1voto

Iridium Punkte 22300

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

1voto

Scott Wisniewski Punkte 23882

Abgesehen von Meta-Daten gibt es wirklich kein solches Ding wie eine Klasse, sobald alles JIT-kompiliert ist. Die Laufzeitdarstellung eines Objekts ist ein Byte-Array groß genug, um alle Felder der Klasse und ihrer Basisklassen sowie einen Objektheader zu speichern, der einen Hash-Code, einen numerischen Typidentifikator und einen Zeiger auf eine gemeinsame V-Tabelle enthält, die Adressen von virtuellen Funktionsüberschreibungen enthält.

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

Eine anonyme Funktion ist eine Funktion, die keinen Namen hat. Sie sind jedoch in der Regel auch mit einem Objekt, das als Closure bezeichnet wird, verbunden, das alle in der umgebenden Methode definierten Parameter und lokalen Variablen enthält, die den "anonymen Delegaten" erstellt haben, der auf die anonyme Funktion zeigt. (Tatsächlich enthält es in der Regel nur die Variablen, die tatsächlich zugegriffen werden).

In jedem Fall ermöglicht das Verschieben der Stapelvariablen auf den Heap dem anonymen Delegaten, seinen definierenden Stapelrahmen zu überleben.

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

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

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

Im Allgemeinen sind anonyme Funktionen ohne Unterstützung für Closures nicht nützlich, daher würde ich sie nicht in Ihre Sprache aufnehmen, wenn keine Closures unterstützt werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X