.NET Dictionary: get or create new

二次信任 提交于 2019-11-27 01:34:24

问题


I often find myself creating a Dictionary with a non-trivial value class (e.g. List), and then always writing the same code pattern when filling in data.

For example:

var dict = new Dictionary<string, List<string>>();
string key = "foo";
string aValueForKey = "bar";

That is, I want to insert "bar" into the list that corresponds to key "foo", where key "foo" might not be mapped to anything.

This is where I use the ever-repeating pattern:

List<string> keyValues;
if (!dict.TryGetValue(key, out keyValues))
  dict.Add(key, keyValues = new List<string>());
keyValues.Add(aValueForKey);

Is there a more elegant way of doing this?

Related questions that don't have answers to this question:

  • Is there an IDictionary implementation that returns null on missing key instead of throwing?
  • Find-or-insert with only one lookup in c# dictionary
  • Dictionary returning a default value if the key does not exist

回答1:


We have a slightly different take on this, but the effect is similar:

public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) 
    where TValue : new()
{
    TValue val;

    if (!dict.TryGetValue(key, out val))
    {
        val = new TValue();
        dict.Add(key, val);
    }

    return val;
}

Called:

var dictionary = new Dictionary<string, List<int>>();

List<int> numbers = dictionary.GetOrCreate("key");

It makes use of the generic constraint for public parameterless constructors: where TValue : new().

To help with discovery, unless the extension method is quite specific to a narrow problem, we tend to place extension methods in the namespace of the type they are extending, in this case:

namespace System.Collections.Generic

Most of the time, the person using the type has the using statement defined at the top, so IntelliSense would also find the extension methods for it defined in your code.




回答2:


As with so many programming problems, when you find yourself doing something a lot, refactor it into a method:

public static void MyAdd<TKey, TCollection, TValue>(
    this Dictionary<TKey, TCollection> dictionary, TKey key, TValue value)
    where TCollection : ICollection<TValue>, new()
{
    TCollection collection;
    if (!dictionary.TryGetValue(key, out collection))
    {
        collection = new TCollection();
        dictionary.Add(key, collection);
    }
    collection.Add(value);
}



回答3:


Ok, different approach:

public static bool TryAddValue<TKey,TValue>(this System.Collections.Generic.IDictionary<TKey,List<TValue>> dictionary, TKey key, TValue value)
    {
        // Null check (useful or not, depending on your null checking approach)
        if (value == null)
            return false;

        List<TValue> tempValue = default(List<TValue>);

        try
        {
            if (!dictionary.TryGetValue(key, out tempValue))
            {
                dictionary.Add(key, tempValue = new List<TValue>());
            }
            else
            {
                // Double null check (useful or not, depending on your null checking approach)
                if (tempValue == null)
                {
                    dictionary[key] = (tempValue = new List<TValue>());
                }
            }

            tempValue.Add(value);
            return true;
        }
        catch
        {
            return false;
        }
    }

In this way you have to "try to add" your value to a generic List of (obviously generalizable to a generic collection), null checking and trying to get existing key/values in your Dictionary. Usage and example:

var x = new Dictionary<string,List<string>>();
x.TryAddValue("test", null); // return false due to null value. Doesn't add the key
x.TryAddValue("test", "ok"); // it works adding the key/value
x.TryAddValue("test", "ok again"); // it works adding the value to the existing list

Hope it helps.




回答4:


And what about this?

var keyValues = dictionary[key] = dictionary.ContainsKey(key) ? dictionary[key] : new List<string>();
keyValues.Add(aValueForKey);


来源:https://stackoverflow.com/questions/16192906/net-dictionary-get-or-create-new

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!