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


182

現在、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");

DictionaryC#の連想配列/ sにある種のリテラル表記はありますか?


C#9には、辞書リテラルの提案が含まれています。以下にその回答を掲載します。夢がかなう!
aloisdgがcodidact.comに移動

回答:


291

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

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

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

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

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


2
ありがとう。Dictionary<string, string>ただし、そのうちの1つを削除することはできますか?それはかなり冗長に見えますが、私は間違っているかもしれません。編集:これは確かにより望ましい方法のようです、ありがとう。
pimvdb 2011

3
@pimvdb:できます。それをとして宣言するとvar、コンパイラはから型を推測しnewます。回答を編集しました。
BoltClock

7
厳密に言うと、それは文字表記ではないことに注意してください...これは初期化のショートカットにすぎません。文字列と一部のプリミティブ型のみがリテラル表現を持っています
Thomas Levesque

「文字列」の1つを削除したい場合-それらは冗長ではありません-1つはキータイプ用で、もう1つは値タイプ用です。辞書に固有のリテラルはありません。この回答で使用される表記は、2つの文字列を受け取る(そしてIEnumerableを実装する)Addメソッドを持つすべてのクラスに一般的です。
Markus Johnsson、2011

1
@マーカス・ジョンソン:彼は文字通り、を意味しましたDictionary<string, string>。私のコードは最初に型を宣言しましたがvar、彼のコメントの後でそれを変更しました。
BoltClock

13

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

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

"data"変数は "unspeakable"匿名型になるため、これはとしてのみ渡すことができますSystem.Object。次に、匿名オブジェクトを辞書に変換できるコードを記述できます。このようなコードはリフレクションに依存するため、遅くなる可能性があります。ただし、を使用System.Reflection.EmitしたりSystem.Linq.Expressions、デリゲートをコンパイルおよびキャッシュして、後続の呼び出しをはるかに高速にすることができます。

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


1
これは、キーのセットが静的である場合にのみ役立ちます。同じ目的でタプルを使用することもできます。
sehe

8

を使用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

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

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

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

このSynthaxにより、C#の辞書での作業がより簡単になり、冗長なコードが削除されます。

GitHubで問題を追跡できます(ここにC#9のマイルストーンがあります)。

編集:この提案は現在拒否されています:

[...]特に不変のディクショナリなど、データの初期化には多くの興味深いユースケースがあると考えています。煩わしいディクショナリを初期化するための既存の構文は見つかりません。また、それを言語機能から多くの利益を得るコード内の頻繁なパターンと見なしません。レコードを初期化し、枯渇させた後、データの初期化の一般的な領域をもう一度検討する必要があると考えています。[...]


1
素晴らしいアイデア、それが実現することを願って、頭のない人のように思えます
jjxtra
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.