协方差/协方差不应该在C#4.5中允许吗? [英] Shouldn't Covariance/Contravariance allow this in C# 4.5?

查看:81
本文介绍了协方差/协方差不应该在C#4.5中允许吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

private Dictionary<Type, List<IDataTransferObject>> dataStore = new Dictionary<Type, List<IDataTransferObject>>();

public void Insert<T>(T dto) where T : IDataTransferObject
{
    if (!dataStore.ContainsKey(typeof(T)))
    {
        dataStore.Add(typeof(T), new List<T>());
    }

    dataStore[typeof(T)].Add(dto);
}

上面的代码在dataStore.Add行上给我一个编译错误,因为它我不喜欢尝试将 List< T> 分配给 List< IDataTransferObject> 。由于我的方法仅将T限制为IDataTransferObject,因此.Net 4中的协方差/相反方的东西不应该允许此代码?

The above code gives me a compile error on the dataStore.Add line because it doesn't like me trying to assign a List<T> to a List<IDataTransferObject>. Since my method restricts T to only IDataTransferObject's shouldn't the covariance/contravariance stuff in .Net 4 allow this code?

我知道我可以将其更改为执行新的 List< IDataTransferObject> ,它可以工作,但是我很好奇为什么原始代码不起作用。

I know I can change it to do new List<IDataTransferObject> and it will work, but I'm curious why the original code doesn't work.

推荐答案

很确定 List< SubClass> List< BaseClass> 。 IEnumerable< T> 可能是,但不是列表,因为您可以自由添加非 T (但仍 IDataTransferObjects )会抛出运行时异常,因此在编译时会被捕获。

Pretty sure a List<SubClass> isn't covariant to List<BaseClass>. IEnumerable<T> maybe, but not List as you can freely add a non-T (but still IDataTransferObjects) which would throw a runtime exception so it's caught at compile time.

虽然您的代码在运行时可能是安全的(如

While your code might be safe at runtime (as you use keys by type), the compiler doesn't know this.

List<Animal> animalList = new List<Animal>();
animalList.Add(new Dog()); //ok!

List<Cat> catList = new List<Cat>();
animalList = catList; //Compiler error: not allowed, but it's what you're trying to do
animalList.Add(new Dog()) //Bad stuff! Trying to add a Dog to a List<Cat>

如果您尝试将其视为,则您正在做的事情将起作用IEnumerable< IDataTransferObject> ,因为那些不能通过代码修改(除非您首先强制转换,否则如果使用错误的类型,它将通过/失败)。但是 List 肯定可以通过编译时代码来更改。

What you're doing would work if you were trying to treat it as IEnumerable<IDataTransferObject> as those cannot by modified by code (unless you cast it first at which point it would pass/fail if you use a bad type). But List can definitely be altered by compile-time code.

编辑:如果您不介意进行强制转换,并且真的想要一个 List< T> (因此您的调用代码是类型安全的,一旦检索就不添加非 T 对象),您可以执行以下操作:

If you don't mind casting, and really want a List<T> (so your calling code is typesafe and not adding non-T objects once retrieved) you might do something like this:

private Dictionary<Type, object> dataStore = new Dictionary<Type, object>();

public void Insert<T>(T dto) where T : IDataTransferObject
{
    object data;
    if (!dataStore.TryGetValue(typeof(T), out data))
    {
        var typedData = new List<T>();
        dataStore.Add(typeof(T), typedData);
        typedData.Add(dto);
    }
    else
    {
        ((List<T>)data).Add(dto);
    }
}


//you didn't provide a "getter" in your sample, so here's a basic one
public List<T> Get<T>() where T : IDataTransferObject
{
    object data;
    dataStore.TryGetValue(typeof(T), out data);
    return (List<T>)data;
}

呼叫代码如下:

Insert(new PersonDTO());
Insert(new OrderDTO());
Insert(new PersonDTO());

List<PersonDTO> persons = Get<PersonDTO>();
List<OrderDTO> orders = Get<OrderDTO>();

Console.WriteLine(persons.Count); //2
Console.WriteLine(orders.Count); //1

因此从外部看,所有API使用都是类型安全的。代替 orders List< IDataTransferObject> (这意味着您可以添加非 OrderDTO 对象),它是强类型的,不能混合和匹配。

So from the outside, all API usage is typesafe. Instead of orders being a List<IDataTransferObject> (which means you can add non-OrderDTO objects), it's strongly typed and cannot be mixed and matched.

当然,在这一点上,实际上并不需要限制为 IDataTransferObject ,但这取决于您和您的API /设计/使用情况。

Of course at this point, there's no real need to constrain to IDataTransferObject, but that's up to you and your API/design/usage.

这篇关于协方差/协方差不应该在C#4.5中允许吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆