Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
IDictionary<;TKey,TValue>;在.NET4中不协变_.net_Dictionary_.net 4.0_Covariance - Fatal编程技术网

IDictionary<;TKey,TValue>;在.NET4中不协变

IDictionary<;TKey,TValue>;在.NET4中不协变,.net,dictionary,.net-4.0,covariance,.net,Dictionary,.net 4.0,Covariance,.NET 4/Silverlight 4中的IDictionary不支持协方差,即,我无法执行 IDictionary<string, object> myDict = new Dictionary<string, string>(); IDictionary myDict=new Dictionary(); 模拟我现在可以用IEnumerables执行的操作 可能归结为KeyValuePair也不是协变的。我觉得字典中应该允许协方差,至少对于值是这样的 那么这是一个

.NET 4/Silverlight 4中的
IDictionary
不支持协方差,即,我无法执行

IDictionary<string, object> myDict = new Dictionary<string, string>();
IDictionary myDict=new Dictionary();
模拟我现在可以用
IEnumerable
s执行的操作

可能归结为
KeyValuePair
也不是协变的。我觉得字典中应该允许协方差,至少对于值是这样的

那么这是一个bug还是一个特性?它会不会出现,也许在.NET37.4中

更新(2年后):

在.NET 4.5中会有一个,但它也不会是协变的
:·/
,因为它派生自
IEnumerable
,并且
KeyValuePair
不是一个接口,因此不能是协变的


BCL团队需要重新设计很多,然后使用一些
ICovariantPair
。强类型索引器sála
对于协变接口,此[TKey]
也是不可能的。类似的结果只能通过放置一个扩展方法
GetValue(这个IReadOnlyDictionary self,TKey)
来实现,这个方法在内部必须调用一个实际的实现,可以说看起来是一个相当混乱的方法。

这是一个特性。NET 4.0仅支持安全协方差。您提到的强制转换有潜在的危险,因为如果可能的话,您可以将非字符串元素添加到字典中:

IDictionary<string, object> myDict = new Dictionary<string, string>();
myDict["hello"] = 5; // not an string
IDictionary myDict=new Dictionary();
myDict[“你好”]=5;//不是字符串
另一方面,
IEnumerable
是一个只读接口。
T
type参数仅在其输出位置(当前属性的返回类型),因此可以安全地将
IEnumerable
视为
IEnumerable

,但是您可以说

myDict.Add("Hello, world!", new DateTime(2010, 1, 27));
这将导致惨败。问题在于
IDictionary
中的
TValue
同时用于输入和输出位置。也就是说:

myDict.Add(key, value);   

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

这是设计的

它会不会出现,也许在.NET37.4中


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

.NET4只支持输出协方差,不支持输入协方差。它与IEnumerable一起工作,因为IEnumerable是只读的。

一种针对特定类型的有用协方差的解决方法

公共静态类字典扩展
{
公共静态IRADONLYDICTIONAL到ADONLYDICTIONAL(
这是我的字典(拖带)
{
var intermediate=toWrap.ToDictionary(a=>a.Key,a=>a.Value!=null?
a、 Value.ToArray().AsEnumerable():null);
var wrapper=新的ReadOnlyDictionary(中间);
返回包装器;
}   
}

我也遇到了类似的问题,但使用的是更专业的派生类型(而不是所有派生的对象)

诀窍是使该方法泛化,并放置一个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; }
}
}
使用系统;
使用System.Collections.Generic;
命名空间泛型测试
{
班级计划
{
静态void Main(字符串[]参数)
{
程序p=新程序();
p、 Run();
}
私家车
{
字典a=新字典{
{1,新的SpecialType1{BaseData=“hello”,Special1=1},
{2,新的SpecialType1{BaseData=“再见”,Special1=2}};
测试(a);
}
无效测试(字典数据),其中Y:BaseType
{
foreach(data.Values中的BaseType x)
{
控制台输出写入线(x.BaseData);
}
}
}
公共类基类
{
公共字符串BaseData{get;set;}
}
公共类SpecialType1:基类型
{
公共int Special1{get;set;}
}
}

Ahh好的,当然,我确实打算只读。NET库确实缺少只读字典类型。有人应该在最近的某一天发布另一个关于这个问题的问题从理论上讲,协方差是安全的,但是.NET1.0的一个怪癖可能会给工作带来些许麻烦。由于
派生[]
被认为是从
基[]
继承的,因此
派生[]
将实现
IList
;这样的
IList
在读取时可以正常工作,但在写入时会抛出异常。“in convariance”是一个误称。这将是相反的,它在.NET4中得到支持,并且在某些场景中非常有用。感谢您提供.NET4.5上的更新。我认为在只读字典上设置协方差会很有用,所以看起来它不受支持,这太糟糕了。可以找到支持向上转换的
IReadOnlyDictionary
包装器。它可以包装字符串字典并将其公开为对象字典。这是一个很好的解决方法!它允许我做代码重用所需的事情,完全避免了协方差带来的问题。
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;
    }   
}
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; }
}
}