C # için Sözlük için gerçek gösterim?


182

Şu anda JavaScript ve C # programlanmış bir sunucu arasında bir WebSocket var. JavaScript'te, ilişkilendirilebilir bir dizi kullanarak verileri kolayca iletebilirim:

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

Sunucu tarafında bu veri nesnesini temsil etmek için bir kullanıyorum Dictionary<string, string>, ancak bu JavaScript'ten daha 'yazarak pahalı':

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

DictionaryC # 'da ilişkisel diziler için gerçek bir gösterim var mı ?


C # 9, Sözlük Değişmezleri için bir teklif içerir. Aşağıda bir cevap gönderdim . Hayalimiz gerçek!
aloisdg taşınma codidact.com

Yanıtlar:


291

Sen kullanmak başlatıcı koleksiyonu sözdizimi, ama yine de bir yapmak gerekir new Dictionary<string, string>kısayol sözdizimi bir grup çevrilmiştir olarak birinci nesneyi Add()(sizin kodu gibi) çağrıları:

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

C # 6'da, artık Sözlük ile daha sezgisel bir sözdizimi ve dizinleyicileri destekleyen diğer tüm türleri kullanma seçeneğiniz vardır . Yukarıdaki ifade şu şekilde yeniden yazılabilir:

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

Toplama başlatıcılardan farklı olarak, uygun bir Add()yöntem yerine dizin oluşturucu ayarlayıcıyı kaputun altına çağırır .


2
Teşekkürler. Dictionary<string, string>Gerçi birini kaldırmak mümkün mü ? Çok gereksiz görünüyor, ama yanılıyor olabilirim. Edit: Bu gerçekten daha tercih edilen bir yol gibi görünüyor, teşekkür ederim.
pimvdb

3
@pimvdb: Evet yapabilirsiniz: bunu bir olarak ilan ederseniz var, derleyici türünü çıkarır new. Cevabımı düzenledim.
BoltClock

7
Unutmayın, tam anlamıyla bir gerçek gösterim değil ... sadece başlatma için bir kısayol. Sadece string ve bazı ilkel türlerin gerçek bir temsili vardır
Thomas Levesque

"String" lerden birini kaldırmak istediğinizi ifade ediyorsanız - bunlar gereksiz değildir - biri anahtar türü için, diğeri de değer türü için. Sözlükler için özel bir bilgi yoktur, bu cevapta kullanılan gösterim, iki dize alan (ve IEnumerable uygulayan) bir Add yöntemi olan tüm sınıflar için geneldir.
Markus Johnsson

1
@Markus Johnsson: Yani, kelimenin tam anlamıyla Dictionary<string, string>,. Kodum aslında türü ilan etti, ben sadece varyorumdan sonra bunu değiştirmişti .
BoltClock

13

Sözlük başlatıcı yanıtı tamamen doğru olsa da, ben bunu işaret edecek başka bir yaklaşım var (ama bunu tavsiye etmeyebilirim). Amacınız kısa süreli API kullanımı sağlamaksa, anonim nesneler kullanabilirsiniz.

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

Bu durumda "data" değişkeni "açıklanamayan" bir anonim türdendir, bu nedenle bunu yalnızca olarak iletebilirsiniz System.Object. Daha sonra anonim bir nesneyi sözlüğe dönüştürebilecek kod yazabilirsiniz. Böyle bir kod, potansiyel olarak yavaş olacak olan yansımayı temel alacaktır. Ancak şunu kullanabilirsiniz System.Reflection.Emitveya System.Linq.Expressionsderlemek ve çok daha hızlı sonraki çağrı yapmak istiyorum bir temsilci önbelleğe.

Asp.net MVC API'leri gördüğüm birçok yerde bu tekniği kullanır. Html Helpers'ın çoğunda, bir nesneyi veya sözlüğü kabul eden aşırı yüklenmeler vardır. API tasarımlarının amacının peşindeyken aynı olduğunu varsayıyorum; yöntem çağrısında kısa sözdizimi.


1
Bu sadece anahtar seti statik olduğunda yardımcı olacaktır. Tuples'ı aynı amaçla da kullanabilirsiniz.
sehe

8

Kullanarak DynamicObject, daha basit bir sözlük başlatıcısı oluşturmak o kadar zor değildir.

Aşağıdaki yöntemi çağırmak istediğinizi düşünün

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

gibi gerçek bir sözdizimi kullanmak

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

Bu, bunun gibi dinamik bir nesne oluşturarak gerçekleştirilebilir

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;
    }
}

6

Sözlük Değişmezlerini Kullan (C # 9 teklifi)

C # 9 Dictionary<TKey,TValue>, Sözlük türü adını veya tür parametrelerini belirtmek zorunda kalmadan başlatılmış nesneler oluşturmak için daha basit bir sözdizimi sunar . Sözlük için tür parametreleri, dizi türü çıkarımı için kullanılan mevcut kurallar kullanılarak çıkarılır.

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

Bu sözdizimi, C # 'daki sözlüklerle çalışmayı kolaylaştırır ve gereksiz kodu kaldırır.

Sorunu GitHub'da takip edebilirsiniz (ve işte C # 9 için kilometre taşı ).

Düzenle: Bu teklif şu anda reddedildi :

[...] Verilerin başlatılması etrafında, özellikle değişmez sözlükler gibi şeyler için bir dizi ilginç kullanım durumu olduğunu düşünüyoruz. Bir sözlüğü başlatmak için mevcut sözdizimini zahmetli bulmuyoruz ya da bunu bir dil özelliğinden çok fayda sağlayacak sık bir kod modeli olarak görmüyoruz. Kayıtları ve solmaları yaptıktan sonra genel veri başlatma alanına tekrar bakılması gerektiğine inanıyoruz. [...]


1
Harika bir fikir, umarım onu ​​yapar, hayır
beyinsiz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.