代码之家  ›  专栏  ›  技术社区  ›  herzmeister

.NET 4中的IDictionary<tkey,tValue>Not协变

  •  55
  • herzmeister  · 技术社区  · 15 年前

    这个 IDictionary<TKey, TValue> 在.NET 4/Silverlight 4中不支持协方差,即我不能执行

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

    类似于我能做的 IEnumerable<T> 现在是。

    可能归结为 KeyValuePair<TKey, TValue> 也不是协变的。我觉得至少在字典中应该允许值的协方差。

    那么这是一个bug还是一个特性?它会不会出现在.NET 37.4中?

    更新(2年后):

    会有一个 IReadOnlyDictionary<TKey, TValue> 在.NET 4.5中,但它也不会协变。 :·/ ,因为它源自 IEnumerable<KeyValuePair<TKey, TValue>> 键值对<tkey,tvalue> 不是接口,因此不能协变。

    BCL团队将不得不重新设计大量的内容来开发和使用 ICovariantPair<TKey, TValue> 相反。也是强类型索引器la this[TKey key] 对于协变接口是不可能的。类似的结束只能通过放置一个扩展方法来实现。 GetValue<>(this IReadOnlyDictionary<TKey, TValue> self, TKey key) 在某种程度上,它必须在内部调用一个实际的实现,这可以说是一个相当混乱的方法。

    5 回复  |  直到 8 年前
        1
  •  47
  •   Mehrdad Afshari    15 年前

    这是一个特色。.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> .

        2
  •  11
  •   jason    15 年前

    但是你可以说

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

    这将是悲惨的失败。问题是 TValue 在里面 IDictionary<TKey, TValue> 用于输入和输出位置。也就是说:

    myDict.Add(key, value);   
    

    TValue value = myDict[key];
    

    那么这是一个bug还是一个特性?

    这是根据设计。

    它会不会出现在.NET 37.4中?

    不,这是天生的不安全。

        3
  •  5
  •   wavydavy    11 年前

    我也遇到过类似的问题,但派生类型更为专业(而不是所有东西都源自的对象)。

    诀窍是使该方法成为通用方法,并放置一个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; }
    }
    }
    
        4
  •  2
  •   Paul Creasey    15 年前

    .NET 4仅支持 外面的 协方差不是 在里面 .它与IEnumerable一起工作,因为IEnumerable是只读的。

        5
  •  0
  •   Ryan    8 年前

    关于特定类型的有用协方差 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;
        }   
    }