如何使用不同的返回码制作自定义词典?

时间:2013-01-16 05:45:22

标签: c# dictionary

  

可能重复:
  How to get null instead of the KeyNotFoundException accessing Dictionary value by key?

我目前在我的项目中有很多Dictionary<string, T>次使用,其中大部分都是这样的:

if (myDic.ContainsKey("some key"))
    localVar = myDic["some key"];

它也不是很有效,因为它会对字典进行两次调用,这可能会消耗资源。 TryGetValue()是一件很酷的事情,但它不会在一行中完成。

如果null没有此类密钥,我只想获得var v = myDic[key]。我该怎么做?

3 个答案:

答案 0 :(得分:4)

您可以使用TryGetValue的扩展方法:

public static U GetValueByKeyOrNull<T, U>(this Dictionary<T, U> dict, T key)
where U : class
{
    U value;
    dict.TryGetValue(key, out value);
    return value;
}

多亏了你能写的

somedict.GetValueByKeyOrNull("key1")

最后我试图做这件事,我想出了一个变体,使用了一个带有显式接口实现的字典类派生:How to get null instead of the KeyNotFoundException accessing Dictionary value by key?

那是

public interface INullValueDictionary<T, U>
    where U : class
{
    U this[T key] { get; }
}

public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
    where U : class
{
    U INullValueDictionary<T, U>.this[T key]
    {
        get
        {
            U val;
            dict.TryGet(key, out val);
            return val;
        }
    }
}

并在任何地方使用它而不是原始字典:

//create some dictionary
NullValueDictionary<int, string> dict = new NullValueDictionary<int, string>
{
    {1,"one"}
};
//have a reference to the interface
INullValueDictionary<int, string> idict = dict;
string val = idict[2]; // null
val = idict[1];        // "one"

答案 1 :(得分:1)

我不喜欢处理null因此我的实现将如下所示:

interface Maybe<T> {
    bool HasValue {get;}
    T Value {get;}
}

class Nothing<T> : Maybe<T> {
    public bool HasValue { get { return false; } }
    public T Value { get { throw new Exception(); } }
    public static const Nothing<T> Instance = new Nothing<T>();
}

class Just<T> : Maybe<T> {
    private T _value;
    public bool HasValue { get { return true; } }
    public T Value { get { return _value; } }
    public Just(T val) {
        _value = val;
    }
}

Maybe是一个可以包含或不包含值的对象。请注意,Nothing类包含静态字段Instance。每次我们需要从函数返回Nothing时,我们都可以使用此值而不是创建新值。

现在,我们需要创建自己的字典类:

class MyDictionary<TKey, TValue>
{
    private Dictionary<TKey, TValue> _dict;

    ...

    public Maybe<TValue> this[TKey key] {
        TValue val;
        if (_dict.TryGetValue(key, out val)) {
            return new Just<TValue>(val);
        return Nothing<TValue>.Instance;
    }
}

这种方法的优点尚不清楚,因为C#没有模式匹配。但可以使用dynamic

进行模拟
void ProcessResult(Just<string> val) {
    Console.WriteLine(val);
}

void ProcessResult(Nothing<string> n) {
    Console.WriteLine("Key not found");
}

var dict = new MyDictionary<string, string>();
...
dynamic x = dict["key"];
ProcessResult(x);

我认为这是非常明确的方式来表达字典不能总是返回有意义的结果。此外,对于读者来说,显然只会为字典中存在的值调用函数重载ProcessResult(Just<T>),并且在未找到键时将调用其他重载。

<强>优点:

  • 类型用作规范。
  • 字典可以包含值和引用类型。

<强>缺点:

  • 更多按键。
  • 处理的复杂性要小得多。

答案 2 :(得分:0)

我决定这样做:

class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            return TryGetValue(key, out value) ? value : default(TValue);
        }
        set { base[key] = value; }
    }
}

它允许我像任何其他字典一样使用它,通过方括号。由于我不打算将值类型用作TValue,我认为这是一个很好的解决方案。