2016-04-28 104 views
1

我有一個IDictionary<string, MyEnum?>集合需要傳遞給一個類來包裝它在IReadOnlyDictionary<string, MyEnum>(注意MyEnum但不是MyEnum?)。只讀集合屬性的類設計

我想出了兩種設計:

  1. 延遲包裝到IReadOnlyDictionary<string, MyEnum>直到屬性訪問:

    public class MyClass 
    { 
        private readonly IEnumerable<KeyValuePair<string, MyEnum?>> _kvps; 
    
        public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps) 
        { 
         _kvps = kvps; 
        } 
    
        public IReadOnlyDictionary<string, MyEnum> Kvps 
        { 
         get 
         { 
          var filtered = from kvp in _kvps 
              where kvp.Value.HasValue 
              select kvp; 
          return new ReadOnlyDictionary<string, MyEnum>(
           filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value); 
         } 
        } 
    } 
    
  2. 在構造

    public class MyClass 
    { 
        public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps) 
        { 
         Kvps = ToReadOnly(kvps); 
        } 
    
        public IReadOnlyDictionary<string, MyEnum> Kvps { get; } 
    
        private static IReadOnlyDictionary<string, MyEnum> ToReadOnly(
         IEnumerable<KeyValuePair<string, MyEnum?>> kvps) 
        { 
         var filtered = from kvp in kvps 
             where kvp.Value.HasValue 
             select kvp; 
         return new ReadOnlyDictionary<string, MyEnum>(
          filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value); 
        } 
    } 
    
急切評估集合

「框架設計指南」中的constructor design部分指出,最小的工作應該在構造函數中完成,所以我選擇第一種方法。但是,這意味着每次致電MyClass.Kvps都會觸發_kvps這個不理想的副本。

我想知道這是一個更好的方法(或有其他方式)在以下方面:

  • 記憶效率(理想情況下只集合的一個副本存儲在MyClass
  • 性能(屬性訪問要快而不應觸發KeyValuePair s的複印件)
+0

如果源字典在構造和屬性訪問之間或連續屬性訪問之間被修改,那麼您的兩個設計具有不同的行爲。你要哪個? – Blorgbeard

+0

@Blorgbeard我想要屬性總是反映源'IDictionary'的最新值。這是否意味着我僅限於我的第一種方法? – rexcfnghk

+0

然後是的,你必須在屬性訪問器中進行過濾。 – Blorgbeard

回答

1

出的兩個要求 - 不要複製的鍵值對,並沒有存儲兩個副本 - 你必須打破一個。

是什麼原因導致我們來看看這一點,並認爲有必須是一個解決辦法是,我們看到TValueTValue?和我們的腦海中想看到他們爲同一類型。但它們不是同一類型。

如果你想象代替TValueTValue?這是兩個不同的類型,像intstring變得清晰,我們希望項目一期集合其他同時過濾的集合。例如,

List<string> GetStringsFromNonNegativeInts(List<int> ints) 
{ 
    return ints.Where(i=>i>-1).Select(i=>i.ToString()).ToList(); 
} 

這正是相同的情況下試圖爲一組TValue?篩選一組TValue,即使沒有字典。這很難看到。 TValueTValue?代碼盲我們。

只有兩種方法可以做到這一點。一種是每次複製,另一種是保持兩個列表同步。

+0

很好的例子。謝謝。 – rexcfnghk

1

編輯:如果你想要最新的源值,最好的辦法就是實現你自己的類實現IReadOnlyDictionary。使用ReadOnlyDictionary<string, MyEnum?>的專用字段初始化此項。每次調用都會執行查找,如果密鑰存在AND HasValue,則返回該值。

請注意,此實現取決於作爲IReadOnlyDictionary傳入的原始值的引用,以避免需要複製值。


public class MyReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue> where TValue : struct 
{ 
    // other methods to implement here... 

    public MyReadOnlyDictionary(IReadOnlyDictionary<TKey, TValue?> kvps) 
    { 
     _kvps = kvps; 
    } 

    private IReadOnlyDictionary<TKey, TValue?> _kvps; 

    new public TValue this[TKey key] 
    { 
     get 
     { 
      TValue? val = _kvps[key]; 
      if (val.HasValue) 
       return val.Value; 
      throw new KeyNotFoundException(); 
     } 
    } 
} 
+0

OP在他的評論中表示他希望每次調用該屬性時都使用最新的源值,因此緩存將無法工作。 – RJM

+0

好點。我更新了我的答案以反映這一點。我認爲上面關於實現一個新的IReadOnlyDictionary實現類的評論是最有效的方法。 – gnalck

+0

我也看了這個方法。處理統計員似乎很痛苦,因爲你必須「假裝」某些項目實際上不在字典中。 –