Literale Notation für Wörterbuch in C #?

181

Ich habe derzeit ein WebSocket zwischen JavaScript und einem in C # programmierten Server. In JavaScript kann ich Daten einfach mit einem assoziativen Array übergeben:

var data = {'test': 'val',
            'test2': 'val2'};

Um dieses Datenobjekt auf der Serverseite darzustellen, verwende ich a Dictionary<string, string>, aber dies ist "typenintensiver" als in JavaScript:

Dictionary<string, string> data = new Dictionary<string,string>();
data.Add("test", "val");
data.Add("test2", "val2");

Gibt es eine Art Literalnotation für assoziative Arrays Dictionaryin C #?

pimvdb
quelle
C # 9 enthält einen Vorschlag für Wörterbuchliterale. Ich poste unten eine Antwort dazu . Unser Traum wird wahr!
Aloisdg wechselt zu codidact.com

Antworten:

291

Sie verwenden die Auflistungsinitialisierersyntax , müssen jedoch new Dictionary<string, string>zuerst ein Objekt Add()erstellen, da die Verknüpfungssyntax in eine Reihe von Aufrufen (wie Ihren Code) übersetzt wird:

var data = new Dictionary<string, string>
{
    { "test", "val" }, 
    { "test2", "val2" }
};

In C # 6 haben Sie jetzt die Möglichkeit, eine intuitivere Syntax mit Dictionary sowie mit jedem anderen Typ zu verwenden, der Indexer unterstützt . Die obige Aussage kann wie folgt umgeschrieben werden:

var data = new Dictionary<string, string>
{
    ["test"] = "val",
    ["test2"] = "val2"
};

Im Gegensatz zu Sammlungsinitialisierern wird hierdurch der Indexer-Setter unter der Haube und nicht eine geeignete Add()Methode aufgerufen.

BoltClock
quelle
2
Vielen Dank. Ist es möglich, eines davon zu entfernen Dictionary<string, string>? Es scheint ziemlich überflüssig, aber ich könnte mich irren. Bearbeiten: Dies scheint in der Tat ein bevorzugterer Weg zu sein, danke.
Pimvdb
3
@pimvdb: Ja, Sie können: es als deklarieren var, der Compiler wird den Typ aus dem ableiten new. Ich habe meine Antwort bearbeitet.
BoltClock
7
Beachten Sie, dass es sich streng genommen nicht um eine wörtliche Notation handelt. Es handelt sich lediglich um eine Verknüpfung für die Initialisierung. Nur Zeichenfolgen und einige primitive Typen haben eine wörtliche Darstellung
Thomas Levesque
Wenn Sie meinen, Sie möchten eine der "Zeichenfolgen" entfernen - sie sind nicht redundant -, ist eine für den Schlüsseltyp, die andere für den Werttyp. Es gibt kein spezifisches Literal für Wörterbücher. Die in dieser Antwort verwendete Notation ist allgemein für alle Klassen mit einer Add-Methode, die zwei Zeichenfolgen akzeptiert (und IEnumerable implementiert).
Markus Johnsson
1
@ Markus Johnsson: Er meinte wörtlich , Dictionary<string, string>. Mein Code deklarierte ursprünglich den Typ, ich hatte ihn gerade varnach seinem Kommentar geändert .
BoltClock
13

Die Antwort auf den Wörterbuchinitialisierer ist zwar völlig korrekt, es gibt jedoch einen anderen Ansatz, auf den ich hinweisen möchte (den ich jedoch möglicherweise nicht empfehle). Wenn Sie eine knappe API-Nutzung wünschen, können Sie anonyme Objekte verwenden.

var data = new { test1 = "val", test2 = "val2"};

Die Variable "data" ist dann von einem "unaussprechlichen" anonymen Typ, sodass Sie dies nur als weitergeben können System.Object. Sie könnten dann Code schreiben, der ein anonymes Objekt in ein Wörterbuch umwandeln kann. Ein solcher Code würde auf Reflexion beruhen, die möglicherweise langsam wäre. Sie können jedoch einen Delegaten verwenden System.Reflection.Emitoder System.Linq.Expressionskompilieren und zwischenspeichern, um nachfolgende Aufrufe viel schneller auszuführen.

Asp.net MVC-APIs verwenden diese Technik an einer Reihe von Stellen, die ich gesehen habe. Viele der HTML-Helfer haben Überladungen, die entweder ein Objekt oder ein Wörterbuch akzeptieren. Ich gehe davon aus, dass das Ziel ihres API-Designs dasselbe ist wie das, wonach Sie suchen. knappe Syntax beim Methodenaufruf.

MarkPflug
quelle
1
Das hilft nur, wenn der Schlüsselsatz statisch ist. Sie können Tupel auch für denselben Zweck verwenden.
sehe
8

Mit DynamicObjectist es nicht so schwierig, einen einfacheren Wörterbuchinitialisierer zu erstellen.

Stellen Sie sich vor, Sie möchten die folgende Methode aufrufen

void PrintDict(IDictionary<string, object> dict) {
    foreach(var kv in dict) {
        Console.WriteLine ("  -> " + kv.Key + " = " + kv.Value);
    }
}

mit einer wörtlichen Syntax wie

var dict = Dict (Hello: "World", IAm: "a dictionary");
PrintDict (dict);

Dies kann erreicht werden, indem ein dynamisches Objekt wie dieses erstellt wird

dynamic Dict {
    get {
        return new DynamicDictFactory ();
    }
}

private class DynamicDictFactory : DynamicObject
{
    public override bool TryInvoke (InvokeBinder binder, object[] args, out object result)
    {
        var res = new Dictionary<string, object> ();
        var names = binder.CallInfo.ArgumentNames;

        for (var i = 0; i < args.Length; i++) {
            var argName = names [i];
            if(string.IsNullOrEmpty(argName)) throw new ArgumentException();
            res [argName] = args [i];
        }
        result = res;
        return true;
    }
}
Krumelur
quelle
6

Verwenden Sie Wörterbuchliterale (C # 9-Vorschlag)

C # 9 führt eine einfachere Syntax ein, um initialisierte Dictionary<TKey,TValue>Objekte zu erstellen , ohne den Namen des Wörterbuchtyps oder die Typparameter angeben zu müssen. Die Typparameter für das Wörterbuch werden unter Verwendung der vorhandenen Regeln abgeleitet, die für die Inferenz des Array-Typs verwendet werden.

// C# 1..8    
var x = new Dictionary <string,int> () { { "foo", 4 }, { "bar", 5 }};   
// C# 9    
var x = ["foo":4, "bar": 5];  

Diese Synthax vereinfacht die Arbeit mit Wörterbüchern in C # und entfernt den redundanten Code.

Sie können das Problem auf GitHub verfolgen (und hier ist der Meilenstein für C # 9 ).

Bearbeiten: Dieser Vorschlag wird derzeit abgelehnt :

[...] Wir glauben, dass es eine Reihe interessanter Anwendungsfälle beim Initialisieren von Daten gibt, insbesondere für Dinge wie unveränderliche Wörterbücher. Wir finden die vorhandene Syntax zum Initialisieren eines Wörterbuchs weder so lästig, noch sehen wir sie als häufiges Muster im Code, das von einer Sprachfunktion stark profitieren würde. Wir sind der Meinung, dass der allgemeine Bereich der Dateninitialisierung erneut überprüft werden sollte, nachdem wir Aufzeichnungen gemacht und verwelkt haben. [...]

aloisdg wechselt zu codidact.com
quelle
1
Tolle Idee, hoffe es schafft es, scheint ein Kinderspiel zu sein
jjxtra