带有基类give的调用泛型无法从基类转换为T

本文关键字:基类 转换 泛型 give 调用 | 更新日期: 2023-09-27 18:00:08

我有以下设置,并且我的对象似乎无法转换为泛型类型。而它实际上是基类。为什么不起作用?在我看来,这太合乎逻辑了。

public class AList<T> where T : A
{
    void DoStuff(T foo)
    {
    }
    void CallDoStuff()
    {
        DoStuff(new A()); // ERROR: Cannot convert A to T
    }
}
public class A
{
}

带有基类give的调用泛型无法从基类转换为T

这里的问题是约束规定T必须是A或从A派生的类
现在,当您用具体类型实例化AList时,T是一个非常具体的类。如果你没有用A本身实例化AList,而是用它的一个子类实例化,那么T就是A的一个子类别。

不能将基类的运行时类型的实例转换为其子类,因为它会错过子类添加的所有信息。

示例:

public class Animal
{
    public int Foo { get; set; }
}
public class Cat : Animal
{
    public int Bar { get; set; }
}
Derived d = new Base();

您希望该代码能够工作吗?当然不是,因为Cat也是Animal,但Animal不是Cat
如果您希望上面的代码能够实际工作,请问问自己执行以下代码时应该发生什么:d.Bar = 42;
Animal不包含Bar的定义。

同样的情况也发生在你的代码中——只是游戏中的泛型稍微模糊了一点。

T也可以是从A派生的类,因此不能将A的实例作为T类型的参数。类似于调用方法,该方法使用int和类型为object的参数。

这与object无法隐式转换为int的原因相同。

该方法需要一个子类,而您正在传递父类,因此需要显式强制转换。

因为你要求T扩展A。所以你可以用A代替T,但不能用T代替A。

如果猫:动物,这并不意味着你总是可以把一只动物变成一只猫。

尝试使用ActivatorT中为您提供A的实例,因为您知道由于您的约束,T必须是A,所以不需要在任何地方使用new A(),因为您有T,所以您只需创建T的实例。

T obj = Activator.CreateInstance<T>();
DoStuff(obj);

或者像其他答案提到的那样,对你的object进行一次测试,但这并不是在所有情况下都有效。

T obj = (T)new A();
DoStuff(obj);