开发者

Literal notation for Dictionary in C#?

I currently have a WebSocket between JavaScript and a server programmed in C#. In JavaScript, I can pass data easily using an associative array:

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

To represent this data object on the server side, I use a Dictionary<string, string>, but this is more 'typing-expensive' than in JavaScript:

Dictionary<string, string> data = ne开发者_JAVA技巧w Dictionary<string,string>();
data.Add("test", "val");
data.Add("test2", "val2");

Is there some kind of literal notation for associative arrays / Dictionarys in C#?


You use the collection initializer syntax, but you still need to make a new Dictionary<string, string> object first as the shortcut syntax is translated to a bunch of Add() calls (like your code):

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

In C# 6, you now have the option of using a more intuitive syntax with Dictionary as well as any other type that supports indexers. The above statement can be rewritten as:

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

Unlike collection initializers, this invokes the indexer setter under the hood, rather than an appropriate Add() method.


While, the dictionary initializer answer is totally correct, there is another approach to this that I would point out (but I might not recommend it). If your goal is to provide terse API usage, you could use anonymous objects.

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

The "data" variable is then of an "unspeakable" anonymous type, so you could only pass this around as System.Object. You could then write code that can transform an anonymous object into a dictionary. Such code would rely on reflection, which would potentially be slow. However, you could use System.Reflection.Emit, or System.Linq.Expressions to compile and cache a delegate that would make subsequent calls much faster.

Asp.net MVC APIs use this technique in a number of places that I've seen. A lot of the Html Helpers have overloads that accept either an object or a dictionary. I assume the goal of their API design is the same as what you are after; terse syntax at the method call.


Use Dictionary Literals (C#9 proposal) [rejected] or the new syntax (beginning with C#9)

C#9 introduces a simpler syntax to create initialized Dictionary<TKey,TValue> objects without having to specify either the Dictionary type name or the type parameters. The type parameters for the dictionary are inferred using the existing rules used for array type inference.

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

This synthax makes the work with dictionaries in C# simpler and removing the redundant code.

You can follow the issue on GitHub (and here is the milestone for C#9).

Edit: This proposal is currently rejected:

[...] We think there are a number of interesting use cases around initializing data, particularly for things like immutable dictionaries. We don't find the existing syntax for initializing a dictionary that onerous, nor do we see it as a frequent pattern in code that would benefit much from a language feature. We thing that the general area of initializing data should be looked at again after we do records and withers. [...]

current milestone:

Literal notation for Dictionary in C#?

Note that beginning with C# 9.0, constructor invocation expressions are target-typed. That is, if a target type of an expression is known, you can omit a type name, as the following example shows:

Dictionary<int, List<int>> lookup = new()
{
    [1] = new() {1, 2, 3},
    [2] = new() {5, 8, 3},
    [5] = new() {1, 0, 4}
};

As the preceding example shows, you always use parentheses in a target-typed new expression.

If a target type of a new expression is unknown (for example, when you use the var keyword), you must specify a type name.

MSDN


Using DynamicObject, it is not that difficult to create a simpler dictionary initializer.

Imagine you want to call the following method

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

using a literal syntax like

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

This can be accomplished by creating a dynamic object like this

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜