2013-01-16 23 views
2

可能重複:
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"]; 

這不是很effecient因爲它會對字典進行兩次調用,這可能會消耗資源。 TryGetValue()是一件很酷的事情,但它不會在一行中完成。如果var v = myDic[key]沒有這樣的密鑰,我只想得到null。我怎麼做?

+0

如果你不願意改變你的字典,如康斯坦丁的答案中提到的那樣,實現空返回的簡單擴展方法也可以。 – ryadavilli

+3

注意:值類型沒有'null'的好概念...所以要注意'字典'並試圖返回類型爲'int'的特殊不存在的值:) –

+0

@AlexeiLevenkov好點。當我解決了這個問題時,我不需要使用值類型爲 – horgh

回答

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,我認爲這是一個足夠好的解決方案。

+0

如果我想創建MyDictionary ?如何檢查字典中是否存在關鍵字? – Lazin

+0

@Lazin正如我上面特別提到的,我不會將這個值類型用作'TValue',所以你不應該這樣做。或者,你可以嘗試使用'MyDictionary ',或者更好的是'int?[]'。 – user1306322

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" 
+0

有什麼辦法嗎?像普通字典一樣,可以使用方括號嗎? – user1306322

+0

@ user1306322你讀過我在這個問題下提到的線程嗎?在那裏你可以找到想法 – horgh

+0

@ user1306322我已經在這個問題中分享了該主題的想法。請考慮。 – horgh

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>)將僅針對字典中存在的值而被調用,並且在未找到密鑰的情況下將調用其他重載。

優點:

  • 類型充當規範。
  • 詞典可以包含值類型和引用類型。

缺點:

  • 更多按鍵。
  • 處理複雜性稍微小一些。
+0

+1:有趣的解決方案。 – horgh