C#中字典的文字表示法?


181

我目前在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#中的关联数组是否有某种文字表示形式?


C#9包含有关字典文字的建议。我在下面发布有关此问题的答案。我们的梦想成真!
aloisdg移至codidact.com,

Answers:


291

您使用集合初始值设定项语法,但是new Dictionary<string, string>由于快捷方式语法已转换为一堆Add()调用(例如您的代码),因此您仍然需要先创建一个对象:

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

在C#6中,您现在可以选择对Dictionary以及支持索引器的任何其他类型使用更直观的语法。上面的语句可以改写为:

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

与集合初始化程序不同,这将在后台调用索引器setter,而不是适当的Add()方法。


2
谢谢。是否可以删除其中之一Dictionary<string, string>?似乎有点多余,但我可能错了。编辑:确实,这似乎是更可取的方式,谢谢。
pimvdb

3
@pimvdb:是的var,您可以:将其声明为a ,编译器将从推断类型new。我编辑了答案。
BoltClock

7
请注意,严格来讲,这不是文字表示法,它只是初始化的快捷方式。只有字符串和某些原始类型具有文字表示形式
Thomas Levesque

如果您要删除“字符串”之一-它们不是多余的-一个用于键类型,另一个用于值类型。没有针对Dictionary的字面量,此答案中使用的符号对于带有两个字符串(并实现IEnumerable)的Add方法的所有类都是通用的。
Markus Johnsson

1
@Markus Johnsson:从字面上看,他的意思是Dictionary<string, string>。我的代码最初声明了该类型,我刚刚var在他的评论后将其更改为。
BoltClock

13

虽然字典初始化程序的答案是完全正确的,但我会指出另一种解决方法(但我可能不建议这样做)。如果您的目标是提供简洁的API使用,则可以使用匿名对象。

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

这样,“数据”变量就属于“无法说服的”匿名类型,因此您只能将传递为System.Object。然后,您可以编写将匿名对象转换成字典的代码。这样的代码将依靠反射,反射可能很慢。但是,您可以使用System.Reflection.Emit,或者System.Linq.Expressions编译和缓存委托,这将使后续调用更快。

我见过的许多地方,Asp.net MVC API都使用了这种技术。许多Html Helper具有接受对象或字典的重载。我认为他们的API设计目标与您追求的目标相同;方法调用时的简洁语法。


1
这仅在键集为静态时才有用。您也可以将Tuples用于相同的目的。
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>对象,而不必指定Dictionary类型名称或类型参数。使用用于数组类型推断的现有规则来推断字典的类型参数。

// 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
好主意,希望它能实现,似乎
没事
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.