Notasi literal untuk Kamus dalam bahasa C #?

182

Saat ini saya memiliki WebSocket antara JavaScript dan server yang diprogram dalam C #. Dalam JavaScript, saya dapat mengirimkan data dengan mudah menggunakan array asosiatif:

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

Untuk mewakili objek data ini di sisi server, saya menggunakan a Dictionary<string, string>, tapi ini lebih 'mengetik mahal' daripada di JavaScript:

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

Apakah ada semacam notasi literal untuk array asosiatif Dictionarydalam C #?

pimvdb
sumber
C # 9 berisi proposal untuk Kamus Sastra. Saya mengirim jawaban tentang itu di bawah ini . Mimpi kita menjadi kenyataan!
aloisdg pindah ke codidact.com

Jawaban:

291

Anda menggunakan sintaks initializer koleksi , tetapi Anda masih harus membuat new Dictionary<string, string>objek terlebih dahulu karena sintaks pintasan diterjemahkan ke sekelompok Add()panggilan (seperti kode Anda):

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

Di C # 6, Anda sekarang memiliki opsi untuk menggunakan sintaks yang lebih intuitif dengan Kamus serta jenis lain yang mendukung pengindeks . Pernyataan di atas dapat ditulis ulang sebagai:

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

Tidak seperti initializers koleksi, ini memanggil setter pengindeks di bawah tenda, daripada Add()metode yang sesuai .

BoltClock
sumber
2
Terima kasih. Apakah mungkin untuk menghapus salah satunya Dictionary<string, string>? Tampaknya agak berlebihan, tetapi saya mungkin salah. Sunting: Ini sepertinya memang cara yang lebih disukai, terima kasih.
pimvdb
3
@ pimvdb: Yup, Anda dapat: mendeklarasikannya sebagai var, kompiler akan menyimpulkan tipe dari new. Saya mengedit jawaban saya.
BoltClock
7
Perhatikan bahwa ini bukan notasi literal, sebenarnya ... itu hanya jalan pintas untuk inisialisasi. Hanya string dan beberapa tipe primitif yang memiliki representasi literal
Thomas Levesque
Jika Anda ingin menghapus salah satu dari "string" s - mereka tidak berlebihan - satu untuk jenis kunci, yang lainnya untuk jenis nilai. Tidak ada literal khusus untuk Kamus, notasi yang digunakan dalam jawaban ini adalah umum untuk semua kelas dengan metode Tambah yang mengambil dua string (dan mengimplementasikan IEnumerable).
Markus Johnsson
1
@ Markus Johnsson: Maksudnya, secara harfiah Dictionary<string, string>,. Kode saya awalnya menyatakan jenisnya, saya baru saja mengubahnya varsetelah komentarnya.
BoltClock
13

Sementara, jawaban penginisialisasi kamus benar-benar benar, ada pendekatan lain untuk hal ini yang akan saya tunjukkan (tapi saya mungkin tidak merekomendasikannya). Jika tujuan Anda adalah untuk menyediakan penggunaan API singkat, Anda dapat menggunakan objek anonim.

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

Variabel "data" kemudian merupakan tipe anonim yang "tidak dapat diucapkan", jadi Anda hanya bisa meneruskannya sebagai System.Object. Anda kemudian dapat menulis kode yang dapat mengubah objek anonim menjadi kamus. Kode seperti itu akan bergantung pada refleksi, yang berpotensi lambat. Namun, Anda bisa menggunakan System.Reflection.Emit, atau System.Linq.Expressionsuntuk mengkompilasi dan men-cache delegasi yang akan membuat panggilan berikutnya lebih cepat.

Asp.net MVC API menggunakan teknik ini di sejumlah tempat yang pernah saya lihat. Banyak Pembantu Html memiliki kelebihan yang menerima objek atau kamus. Saya berasumsi tujuan desain API mereka sama dengan apa yang Anda cari; sintaks singkat di pemanggilan metode.

MarkPflug
sumber
1
Itu hanya akan membantu ketika set kunci statis. Anda juga dapat menggunakan Tuples untuk tujuan yang sama.
lihat
8

Menggunakannya DynamicObject, tidaklah sulit untuk membuat penginisialisasi kamus yang lebih sederhana.

Bayangkan Anda ingin memanggil metode berikut

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

menggunakan sintaks literal seperti

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

Ini dapat dicapai dengan membuat objek dinamis seperti ini

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
sumber
6

Gunakan Kamus Sastra (proposal C # 9)

C # 9 memperkenalkan sintaksis yang lebih sederhana untuk membuat Dictionary<TKey,TValue>objek yang diinisialisasi tanpa harus menentukan nama jenis Kamus atau parameter tipe. Parameter tipe untuk kamus disimpulkan menggunakan aturan yang ada yang digunakan untuk inferensi tipe array.

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

Sintaks ini membuat kerja dengan kamus di C # lebih sederhana dan menghapus kode yang berlebihan.

Anda dapat mengikuti masalah di GitHub (dan ini adalah tonggak sejarah untuk C # 9 ).

Sunting: Proposal ini saat ini ditolak :

[...] Kami pikir ada sejumlah kasus penggunaan yang menarik di sekitar menginisialisasi data, terutama untuk hal-hal seperti kamus yang tidak dapat diubah. Kami tidak menemukan sintaksis yang ada untuk menginisialisasi kamus yang memberatkan, kami juga tidak melihatnya sebagai pola yang sering dalam kode yang akan mendapat banyak manfaat dari fitur bahasa. Kita hal bahwa area umum menginisialisasi data harus dilihat lagi setelah kita melakukan catatan dan layu. [...]

aloisdg pindah ke codidact.com
sumber
1
Gagasan hebat, harap itu berhasil, sepertinya seperti tidak punya otak
jjxtra