2010-01-27 59 views
50

IDictionary<TKey, TValue>在.NET 4/Silverlight的4不支持协方差,即我不能做的IDictionary <TKEY的,TValue>中在.NET 4不是协变

IDictionary<string, object> myDict = new Dictionary<string, string>(); 

模拟到我可以用做IEnumerable<T>现在。

大概归结为KeyValuePair<TKey, TValue>也不是协变。我认为字典中至少应该允许协变量的值。

那么,这是一个错误或功能?它会不会来,也许在.NET 37.4?

UPDATE(2年后):

会有在.NET 4.5的IReadOnlyDictionary<TKey, TValue>,但它不会被协变要么:·/,因为它是从IEnumerable<KeyValuePair<TKey, TValue>>派生,并且KeyValuePair<TKey, TValue>不是接口,因此不能是协变的。

BCL团队将不得不重新设计很多来使用而不是使用ICovariantPair<TKey, TValue>。对于协变接口,强类型索引器也是不可能的。类似的结局只能通过在某个地方放置一个扩展方法GetValue<>(this IReadOnlyDictionary<TKey, TValue> self, TKey key)来实现,这个方法在某种程度上必须在内部调用一个实际的实现,这可能看起来像一个相当混乱的方法。

+7

感谢您提供.NET 4.5的更新。恕我直言,在只读字典上使用协变会很有用,所以它看起来不像支持它。 – dcstraw 2012-03-21 20:12:53

回答

46

这是一个功能。 .NET 4.0仅支持安全协方差。你提到中投潜在危险的,因为你可以在非字符串元素添加到字典中,如果这是可能的:

IDictionary<string, object> myDict = new Dictionary<string, string>(); 
myDict["hello"] = 5; // not an string 

在另一方面,IEnumerable<T>是一个只读接口。 T类型参数仅在其输出位置(返回类型为Current属性),因此将IEnumerable<string>视为IEnumerable<object>是安全的。

+0

呵呵,当然,我确实打算只读使用。 .NET库肯定会错过只读字典类型。有人应该在这些日子之后发表关于这个问题的另一个问题。 ;-) – herzmeister 2010-01-27 19:11:50

+1

理论上协变是安全的,但.Net 1.0的一个怪癖可能会在作品中抛出一个小小的扳手。由于'Derived []'被认为是从'Base []'继承的,'Derived []'将实现'IList ';这样的'IList '可以正常读取,但写入时会抛出异常。 “协方差”中的“ – supercat 2012-12-03 18:01:23

11

但你可以说

myDict.Add("Hello, world!", new DateTime(2010, 1, 27)); 

这将惨遭失败。问题是IDictionary<TKey, TValue>中的TValue用于输入和输出位置。即:

myDict.Add(key, value); 

TValue value = myDict[key]; 

所以是错误或功能?

这是设计。

它会不会来,也许在.NET 37.4?

不,它本质上是不安全的。

2

.NET 4仅支持out协方差不是in。它适用于IEnumerable,因为IEnumerable是只读的。

+10

”是一个用词不当。这将是矛盾的,它在.NET 4中得到了支持,并且在某些情况下很有用。 – dcstraw 2012-03-21 20:08:51

0

一个解决特定类型有用的协方差对IDictionary

public static class DictionaryExtensions 
{ 
    public static IReadOnlyDictionary<TKey, IEnumerable<TValue>> ToReadOnlyDictionary<TKey, TValue>(
     this IDictionary<TKey, List<TValue>> toWrap) 
    { 
     var intermediate = toWrap.ToDictionary(a => a.Key, a => a.Value!=null ? 
             a.Value.ToArray().AsEnumerable() : null); 
     var wrapper = new ReadOnlyDictionary<TKey, IEnumerable<TValue>>(intermediate); 
     return wrapper; 
    } 
} 
5

我也有类似的问题,但更多的专业派生类型(而不是它的一切派生自对象)

诀窍是使该方法通用,并将where子句放入相关限制。 假设您正在处理基类型和派生类型,以下工作:

using System; 
using System.Collections.Generic; 

namespace GenericsTest 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     Program p = new Program(); 

     p.Run(); 
    } 

    private void Run() 
    { 

     Dictionary<long, SpecialType1> a = new Dictionary<long, SpecialType1> { 
     { 1, new SpecialType1 { BaseData = "hello", Special1 = 1 } }, 
     { 2, new SpecialType1 { BaseData = "goodbye", Special1 = 2 } } }; 

     Test(a); 
    } 

    void Test<Y>(Dictionary<long, Y> data) where Y : BaseType 
    { 
     foreach (BaseType x in data.Values) 
     { 
      Console.Out.WriteLine(x.BaseData); 
     } 
    } 
} 

public class BaseType 
{ 
    public string BaseData { get; set; } 
} 

public class SpecialType1 : BaseType 
{ 
    public int Special1 { get; set; } 
} 
} 
+0

这是一个很好的解决方法!它使我能够完成我需要做的代码重用,并且完全避免了协方差会引入的问题。 – jltrem 2014-11-11 20:11:12

相关问题