web-dev-qa-db-ja.com

C#の辞書のリテラル表記?

現在、JavaScriptとC#でプログラムされたサーバーの間にWebSocketがあります。 JavaScriptでは、連想配列を使用してデータを簡単に渡すことができます。

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

サーバー側でこのデータオブジェクトを表すには、Dictionary<string, string>を使用しますが、これはJavaScriptよりも「型付けコストが高い」です。

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

C#の連想配列/ Dictionarysに何らかのリテラル表記はありますか?

163
pimvdb

collection initializer 構文を使用しますが、ショートカット構文が(コードのような)Add()呼び出しの束に変換されるため、最初にnew Dictionary<string, string>オブジェクトを作成する必要があります。

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

C#6では、Dictionaryでより直感的な構文を使用するオプションと、 indexers をサポートする他のタイプを使用できるようになりました。上記のステートメントは次のように書き換えることができます。

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

コレクション初期化子とは異なり、これは適切なAdd()メソッドではなく、内部でインデクサーセッターを呼び出します。

267
BoltClock

辞書初期化の答えは完全に正しいですが、これに対する別のアプローチがあります(ただし、お勧めしません)。目的が簡潔なAPIの使用を提供することである場合、匿名オブジェクトを使用できます。

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

その場合、「データ」変数は「話すことのできない」匿名型であるため、System.Objectとしてのみ渡すことができます。その後、匿名オブジェクトを辞書に変換できるコードを作成できます。このようなコードはリフレクションに依存するため、潜在的に低速になります。ただし、System.Reflection.EmitまたはSystem.Linq.Expressionsを使用して、後続の呼び出しをより高速にするデリゲートをコンパイルおよびキャッシュできます。

Asp.net MVC APIは、私が見た多くの場所でこの手法を使用しています。多くのHtmlヘルパーには、オブジェクトまたは辞書のいずれかを受け入れるオーバーロードがあります。 API設計の目標は、あなたが求めているものと同じだと思います。メソッド呼び出しでの簡潔な構文。

12
MarkPflug

DynamicObjectを使用すると、より単純な辞書初期化子を作成するのはそれほど難しくありません。

次のメソッドを呼び出したいと想像してください

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

次のようなリテラル構文を使用します

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

これは、次のような動的オブジェクトを作成することで実現できます

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
Krumelur

辞書リテラルを使用する(C#9提案)

C#9では、Dictionary型名または型パラメーターを指定せずに、初期化されたDictionary<TKey,TValue>オブジェクトを作成するための簡単な構文が導入されています。辞書の型パラメーターは、配列型の推論に使用される既存の規則を使用して推測されます。

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

このシンタックスにより、C#の辞書を使用した作業が簡単になり、冗長なコードが削除されます。

GitHub で問題をフォローできます(そして、これは C#9のマイルストーン です)。

1
aloisdg