【问题标题】:C# Casting Generic Child Type to ParentC# 将通用子类型转换为父类型
【发布时间】:2017-06-18 12:48:40
【问题描述】:

假设我们有这些类型:

class A {}
class B : A {}

class X<T> {}

为什么我们不能这样做?

X<A> var = new X<B>();

有没有可用的解决方法?

[编辑] 我尝试使用协方差,但它失败了,因为我想访问 X 内的 T 类型的属性,而 C# 不允许在接口中使用 T 类型:

interface IX<out T> {
    T sth {set; get;}
}

class X<T>: IX<T> {
    T sth { set; get; }
}

[编辑 2] 我也试过了,但失败了:

class X<T> where T : A
{
    public T sth { set; get; }

    public static implicit operator X<T>(X<B> v)
    {
        return new X<T>
        {
            sth = v.sth,
        };
    }
}

奇怪的是,C# 不允许对 'sth' 进行强制转换。

【问题讨论】:

  • [Edit 2] 中,当您说 new X&lt;T&gt; { ... } 时,请记住 T 在运行时可以替换为任何具体类型。例如,如果T 恰好是class Evil : A 类型怎么办?然后将v.sth 类型为B 分配给Evil 类型的属性。但它们没有兼容的类型。它们之间唯一的“关系”(BEvil)是两者都派生自A。所以B 不是Evil,所以分配是非法的。由于 T 的某些替换赋值是非法的,所以一般来说赋值是非法的。
  • @JeppeStigNielsen 你是对的 [编辑 2]

标签: c# generics inheritance


【解决方案1】:

问题是类不支持协变和逆变,只支持接口:

class A { }
class B : A { }

class X<T> : P<T> { }

interface P<out T>
{
}

...

P<A> var = new X<B>();

Covariance and Contravariance FAQ

【讨论】:

  • 值得指出的是,类不支持协变和逆变,这就是我们使用接口的原因。
  • 我不能使用协方差,因为我在 A 中有一些 T 类型的属性。
【解决方案2】:

你需要协方差(用out这个词标记类型参数T):

interface IX<out T> {}

这仅允许用于接口类型(和委托类型)。并且B类型必须是引用类型(class这样就可以了)。

那么这很好:

IX<B> ixb = ...;
IX<A> ok = new IX<B>();

【讨论】:

  • 我不能使用协方差,因为我在 A 中有一些 T 类型的属性。
  • 我不确定我是否可以关注你。如果属性可以是set,则不允许使用out,因为它会破坏事物。就像如果你有一个 IList&lt;Cat&gt;,并且 if IList&lt;&gt; 可能是协变的,即使它拥有一个带有 set 访问器的索引器,那么你可以处理该列表作为IList&lt;Animal&gt;,称它为animalList。然后animalList[0] = new Elephant(); 将在猫列表中插入一头大象。你现在能明白为什么具有set 访问器的T 类型的属性使得无法在T 中请求协方差。 (比较IReadOnlyList&lt;out T&gt;,它只有get,没有set。)
猜你喜欢
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多