【问题标题】:Understanding C#'s Type converting [duplicate]了解 C# 的类型转换 [重复]
【发布时间】:2017-04-04 11:14:19
【问题描述】:

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

类:

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...

谢谢你的解释

【问题讨论】:

  • 肯定是因为 Foo 是 BaseObjectWithID 和 extras,而 fooRef 使用 foo,BaseObjWithId 是一个较小的版本它不一样
  • 因为你想做什么是没有意义的。你可以施放它,但它没有任何目的。
  • 由于FooRef 与具体类Foo 的实例相关联,因此无法将其与其基类绑定,除非您使FooRef 过于通用,这与类型转换无关关于泛型
  • 仅仅因为 Foo 继承自 BaseObjWithId 并不意味着 BaseReference&lt;Foo&gt; 继承自 BaseReference&lt;BaseObjWithId&gt; - 它不是 - 它们是两种不同的类型。
  • Cage&lt;Animal&gt; 是一个可以容纳任何动物的笼子。 AquariumCage&lt;Fish&gt;。那么您可以在需要Aquarium 的地方使用Cage&lt;Animal&gt; 吗?不;水族馆保证只有鱼出来,但Cage&lt;Animal&gt; 可以放出老虎。您可以在需要Cage&lt;Animal&gt; 的地方使用Aquarium 吗?不可以。您可以将长颈鹿放入Cage&lt;Animal&gt;,但不能放入Aquarium。由于不可能双向转换,所以AquariumCage&lt;Animal&gt;之间一定存在no类型关系。

标签: c#


【解决方案1】:

您误解了泛型与类型继承相关的工作原理。您可以将FooRef 类型的对象转换为BaseReference&lt;Foo&gt; 类型的引用,因为FooRef 继承自BaseReference&lt;Foo&gt;。但是,您不能将 BaseReference&lt;Foo&gt; 转换为 BaseReference&lt;BaseObjWithID&gt;,因为与它们用作泛型类型参数的类型不同,这两个泛型类没有这种联系。

举个例子:

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

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

Fruit f = new Apple();

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

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

List&lt;Fruit&gt;List&lt;Apple&gt; 是完全不同的类。它们之间没有直接的转换,无论是隐式的还是显式的。

【讨论】:

    【解决方案2】:

    你在搜索什么,叫covariance。在你的情况下 - 泛型的协方差。根据this article,它仅针对有限的类型集实现:

    这很好用:

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

    这不起作用:

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

    因此,在您的情况下,FooRef 直接派生自 BaseReference&lt;Foo&gt;,因此它可以转换为这种类型,而由于泛型参数协方差的问题,c# 不能简单地将 BaseReference&lt;Foo&gt; 转换为 BaseReference&lt;BaseObjWithId&gt;

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

    【讨论】:

      猜你喜欢
      • 2011-03-17
      • 1970-01-01
      • 2013-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      相关资源
      最近更新 更多