理解C#的类型转换

时间:2017-04-04 11:14:20

标签: c#

我不明白为什么这不起作用:

类:

public abstract class BaseObj
{

    public bool IsValid => GetValidationErrors().Count == 0;
}

public class BaseObjWithId: BaseObj 
{
    public int Id { get; set; }
}

public class BaseReference<T> : BaseObj where T : BaseObjWithId
{

    public T ObjReference { get; set; }

}

public class Foo: BaseObjWithId
{
    public string Name{get;set;}
}

public class FooRef : BaseReference<Foo>
{

}

代码语句:

    BaseReference<BaseObjWithId> foo= new FooRef();
  

错误CS0029无法隐式转换类型...

这有效:

    BaseReference<Foo> foo= new FooRef();

但我不明白为什么,因为Foo是一个BaseObjWithId ......

感谢您的解释

2 个答案:

答案 0 :(得分:1)

您误解了泛型在类型继承方面的工作原理。您可以将FooRef类型的对象强制转换为BaseReference<Foo>类型的引用,因为FooRef继承自BaseReference<Foo>。但是,您不能将BaseReference<Foo>强制转换为BaseReference<BaseObjWithID>,因为与它们用作泛型类型参数的类型不同,这两个泛型类没有这样的连接。

采用以下示例:

public class Fruit {}
public class Apple : Fruit {}

任何Apple对象都可以存储在Fruit引用中,因为继承可以确保它们之间的关系检出:

Fruit f = new Apple();

但是,在涉及泛型的情况下,每次使用不同的类型参数创建类的泛型版本时,这些版本都被视为完全不同的类型。例如,虽然上面的隐式转换会起作用,但以下内容将失败:

List<Fruit> f = new List<Apple>();

List<Fruit>List<Apple>是完全不同的类。它们之间没有隐式或明确的直接转换。

答案 1 :(得分:1)

您在搜索什么,名为covariance。在你的情况下 - 泛型的协方差。根据{{​​3}},它仅适用于有限的类型集:

这很好用:

IEnumerable<Derived> b = new List<Derived>();
IEnumerable<Base> a = b;

这不起作用:

IList<Derived> b = new List<Derived>();
IList<Base> a = b;

因此,在您的情况下,FooRef直接来自BaseReference<Foo>,因此可以将其转换为此类型,而c#不能简单地将BaseReference<Foo>转换为BaseReference<BaseObjWithId>因为泛型参数协方差的问题。

可能有一些变通方法,分离的方法,从一种类型到另一种类型的硬编码转换,但是,我想,应该避免这种行为。