5 Stimmen

C# Array-Initialisierung

Als jemand mit einem Hintergrund in C, C++ und Assembler hat mich an C# immer gestört, dass ich so etwas nicht tun kann:

struct OperatorType
{
    string Operator;
    TokenType Type;
}

protected static OperatorType[] Operators = {
    { "{", TokenType.OpenBrace }
};

Ich möchte dies zu deklarieren, so dass es nicht Zuweisung und Initialisierung zur Laufzeit erfordert, aber C# wird es nicht zulassen.

Ja, ich verstehe, dass ich die Initialisierung mit new OperatoryType() { Operator = "{", Type = TokenType.OpenBrace } . Aber erfordert das nicht eine Zuweisung und Initialisierung von Speicher zur Laufzeit? Ich weiß, es ist nicht so viel Overhead, aber ich verstehe nicht, warum es hier notwendig ist.

Kann jemand erklären, warum dieses Bit der zusätzlichen Overhead von C# erforderlich ist, oder möglicherweise eine Möglichkeit, dies ohne die Laufzeitzuweisung zu tun?

9voto

Reed Copsey Punkte 536986

Zuweisungen, ob in C# oder C++, erfordern immer eine Zuweisung zur Laufzeit. Es ist mehr eine Frage der quand die Zuteilungen erfolgen.

Wenn Sie in einem statischen Konstruktor in C# zuweisen, werden Sie irgendwann vor der ersten Verwendung des Typs zuweisen. Das sollte sicher sein und im Vergleich zu Ihrer C++-Version keinen zusätzlichen Overhead verursachen.

Auch eine Sache zu erkennen - Laufzeit Zuweisungen in C # neigen dazu, viel billiger als C + + sein. Dies ist ein großer Vorteil des Garbage Collectors. Es ist sehr wahrscheinlich, dass dies ein klassischer Fall von verfrühter Optimierung ist. Ich würde empfehlen, sich darüber keine Gedanken zu machen, es sei denn, Sie haben ein echtes, gemessenes Leistungsproblem gefunden.

5voto

Gabe Punkte 82268

Das Problem bei der einfachen Abbildung statischer Daten aus einer Binärdatei ist, dass das Format aller Daten zur Kompilierungszeit eingefroren werden muss. Da die Laufzeit das Layout von Strukturen (einschließlich Strings und Arrays) bestimmt, kann der Compiler nicht wissen, wie das Layout aussehen wird. Selbst wenn der Compiler das Layout der aktuellen Laufzeit ausgibt, könnte es von zukünftigen Laufzeiten durchbrochen werden. Das bedeutet, dass nur Strukturen mit explizitem Layout, die in dieser Assembly definiert wurden, statisch aus einer Datei gemappt werden können, was offen gesagt nicht sehr nützlich ist.

Die C# Sprachspezifikation 4.0, Abschnitt 7.6.10.4 sagt:

Außer in einem unsicheren Kontext (§18.1) ist das Layout von Arrays nicht spezifiziert.

In 18.5.8:

Die Reihenfolge, in der die Mitglieder in eine Struktur gepackt werden, ist nicht spezifiziert.

Das Layout von string wurde zwischen .NET 3.5 und 4.0 geändert (ein Feld wurde entfernt); es wurde von

[NonSerialized]
private int m_arrayLength;
[NonSerialized]
private char m_firstChar;
[NonSerialized]
private int m_stringLength;

zu

[NonSerialized, ForceTokenStabilization]
private char m_firstChar;
[NonSerialized]
private int m_stringLength;

In C oder C++ ist dies kein Problem, da der Compiler das Layout von Structs bestimmt. Das bedeutet natürlich auch, dass Sie alles, was eine Struktur/Klasse verwendet, neu kompilieren müssen, um ihr Layout zu ändern.

2voto

BrandonAGr Punkte 5597

Sie könnten einen Nicht-Standard-Konstruktor verwenden, um eine etwas effizientere Version als die Objektinitialisierungssyntax zu erhalten. Es gibt nicht wirklich eine Laufzeitzuweisung außer dem eigentlichen Operators-Array, der Konstruktor wird einfach für jede Position in diesem Array aufgerufen

enum TokenType { OpenBrace, T2 };

struct OperatorType
{
    string Operator;
    TokenType Type;

    public OperatorType(string op, TokenType type)
    {
        Operator = op;
        Type = type;
    }
}

static OperatorType[] Operators = {
    new OperatorType( "{", TokenType.OpenBrace )
};

0voto

Cheng Chen Punkte 40879

Eine einfache Antwort auf Ihre Frage: durch Design. Und ich glaube, dass die Syntax in Ihrer Frage theoretisch umsetzbar ist. Aber wie Eric Lippert oft beantwortet diese Fragen wie "warum kann ich nicht ... in C #":

weil niemand jemals spezifiziert, implementiert und getestet hat, dokumentiert und ausgeliefert hat. Alle sechs dieser Dinge sind notwendig um eine Funktion zu verwirklichen.

0voto

Chuck Savage Punkte 11491

Wenn Sie nicht wollen, dass es zur Laufzeit initialisiert wird, dann erstellen Sie es im statischen Konstruktor. Er wird also erst erstellt, wenn Sie die Klasse Operators zum ersten Mal aufrufen.

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