开发者

How to write an API that accepts a series of anonymous dictionary items?

I frequently find myself needing to wri开发者_开发技巧te APIs that involve key value pairs, when I work with this generally I'll end up with a List<KeyValuePair<string,string>> or similar type collection object which lets me write operations very easily.

The only downside I've come across is adding multiple items to this collect usually results in a very noisy code block such as

MyDictionary.Put(new KeyValuePair<string, string>("a","1"), 
                 new KeyValuePair<string, string>("b","2"), 
                 new KeyValuePair<string, string>("c","3"))

I would much rather be able to do

MyDictionary.Put( {"a","1"},  {"b","2"},  {"c","3"})

A few times I've tried to accomplish and always end up stumbling over what C# expects exactly as the syntax for this.


Collection initialisers allow much of that;

var data = new Dictionary<string,string> {
    {"a","1"},
    {"b","2"},
    {"c","3"}
};

Another way to approach this is to pass just object an use reflection, passing (for example):

new { a = "1", b = "2", c = "3" }

A nice feature of the last option is that you can also pass in your domain entities, and you can perhaps use richer metadata (attributes etc) - but when used in high volume reflection by itself can be slow unless you take steps to optimise for it. If you aren't using it in a tight loop it should be ok even with reflection (and without optimisation).


For literals, how about ...

MyDictionary.Put("a=1", "b=2", "c=3");

implemented something like ...

void Put(params string[] nameEqualValues)
{
    foreach (string nameEqualValue in nameEqualValues)
    {
        int iEquals = nameEqualValue.IndexOf('=');
        if (iEquals < 0)
        {
            throw new ApplicationException(...);
        }
        string name = nameEqualValue.Substring(0, iEquals);
        string val = nameEqualValue.Substring(iEquals + 1);

        this.PutNameValue(name, val);
    }
}

Combining and then splitting strings is a bit of overhead, but it doesn't sound as though performance is a critical concern.

Mind you this breaks down if you're not dealing with literals, worse than what you started with ...

MyDictionary.Put(d + "=" + x, e + "=" + y);
MyDictionary.Put(String.Format("{0}={1}", d, x), ...);

I'd probably suck it up and stick with "params string[]", or call Put multiple times. (Or use python ;)


Require that params come in pairs and treat evens (zero, two, ...) as keys and odds as values:

void Put(params string[] items)
{
    if (items.Length % 2 != 0) throw new ArgumentException("Expected even number");

    for (int i = 0; i < items.Length; i += 2)
    {
        this.myDict[items[i]] = items[i+1];
    }
}


I cannot figure out a very clean way of doing this, but one workaround for lesser typing can be:

public class MyDictionary : List<KeyValuePair<string, string>>
{
    ...

    public void Put(params string[][] p)
    {
        foreach (var a in p)
            Add(new KeyValuePair<string, string>(a[0], a[1]));
    }
}

which can be called like this:

MyDictionary.Put(new[] {"a", "1"}, new[] {"b", "2"}, new[] {"c", "3"});

But this is a definite memory waste and also very inefficient coding.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜