【问题标题】:Why casting with generic types does not work? [duplicate]为什么使用泛型类型进行强制转换不起作用? [复制]
【发布时间】:2019-12-04 14:30:12
【问题描述】:

大家好, 所以我只想使用泛型和强制转换。但是由于某种原因不起作用,我不知道为什么。

abstract class BaseModel {}

    class NewModel : BaseModel {}

    class BaseRepo<T> where T : BaseModel {}

    class NewRepo : BaseRepo<NewModel> {}

    class Test
    {
        public void TestMethod()
        {
            BaseRepo<BaseModel> t1 = new BaseRepo<BaseModel>();
            BaseRepo<NewModel> t2 = new NewRepo();
            BaseRepo<BaseModel> t3 = new BaseRepo<NewModel>();
            // Cannot convert initializer type 'TestGeneric.BaseRepo<TestGeneric.NewModel> to target type 'TestGeneric.BaseRepo<BaseModel>'.
            // Cannot implicitly convert type 'TestGeneric.BaseRepo<TestGeneric.NewModel>' to 'TestGeneric.BaseRepo<TestGeneric.BaseModel>'.
            // Type 'NewModel' doesn't match expected type 'BaseModel'.
            // Cannot convert source type 'TestGeneric.BaseRepo<TestGeneric.NewModel>' to target type 'TestGeneric.BaseRepo<TestGeneric.BaseModel>'.

            BaseRepo<BaseModel> t4 = new NewRepo();
            // Cannot convert initializer type 'TestGeneric.BaseRepo<TestGeneric.NewModel> to target type 'TestGeneric.BaseRepo<BaseModel>'.
            // Cannot implicitly convert type 'TestGeneric.NewRepo' to 'TestGeneric.BaseRepo<TestGeneric.BaseModel>'.
            // Cannot convert source type 'TestGeneric.NewRepo' to target type 'TestGeneric.BaseRepo<TestGeneric.BaseModel>'.
        }
    }

我只是不明白为什么 t3 和 t4 抛出异常同时 t1 和 t2 工作。甚至 NewModel 是 BaseModel 的子类,最后两个不起作用。

【问题讨论】:

  • 检查副本 - 特别是我的 answer。我认为这很容易理解。

标签: c# generics .net-core types


【解决方案1】:

这是由于泛型的协方差特性:

根据有关此 tpoic 的 Microsoft 文档:

协变和逆变是指以下能力的术语 使用更派生的类型(更具体)或更少派生的类型(更少 具体)比最初指定的。泛型类型参数支持 协变和逆变提供更大的灵活性 分配和使用泛型类型。当你提到一种类型时 系统,协变,逆变和不变性具有以下 定义。这些示例假设一个名为 Base 的基类和一个派生类 名为 Derived 的类。

协方差

使您能够使用比最初指定更多的派生类型。

您可以分配一个 IEnumerable (IEnumerable(Of 派生)在 Visual Basic 中)到 IEnumerable 类型的变量。

逆变

使您能够使用比原来更通用(较少派生)的类型 指定。

您可以在 Visual 中分配一个 Action (Action(Of Base) 的实例 Basic) 到 Action 类型的变量。

不变性

表示只能使用最初指定的类型;所以一个 不变的泛型类型参数既不是协变的,也不是 逆变的。

您不能在 Visual 中分配 List (List(Of Base) 的实例 Basic) 到 List 类型的变量,反之亦然。

协变类型参数使您能够进行看起来 很像普通的多态,如下代码所示。

C# 

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

因此,您可以使用接口,例如将代码更改为以下内容:

创建一个ICovariant接口并使用它代替基类BaseRepo

public interface ICovariant<out T> where T : BaseModel
{

}

然后更改您的BaseRepo,如下所示:

public class BaseRepo<T> : ICovariant<T> where T : BaseModel { }

现在你可以这样做了:

BaseRepo<BaseModel> t1 = new BaseRepo<BaseModel>();
BaseRepo<NewModel> t2 = new NewRepo();
ICovariant<BaseModel> t3 = new BaseRepo<NewModel>();
ICovariant<BaseModel> t4 = new NewRepo();

下面的孔代码:

public interface ICovariant<out T> where T : BaseModel
{

}

public abstract class BaseModel { }

public class NewModel : BaseModel { }

public class BaseRepo<T> : ICovariant<T> where T : BaseModel { }

class NewRepo : BaseRepo<NewModel> { }

class Test
{
    public void TestMethod()
    {
        BaseRepo<BaseModel> t1 = new BaseRepo<BaseModel>();
        BaseRepo<NewModel> t2 = new NewRepo();
        ICovariant<BaseModel> t3 = new BaseRepo<NewModel>();
        ICovariant<BaseModel> t4 = new NewRepo();
    }
}

Covariance and Contravariance in Generics

Variance in Generic Interfaces (C#)

【讨论】:

  • 是的,我知道。 VS 向我展示了这个选项。但这有效:BaseModel base = new NewModel() 所以我不明白如果我将它用作通用,为什么它不起作用。这是我真正的问题。
  • @DavidSzilagyi,我已经更新了我的答案,希望对你有所帮助。
  • @DavidSzilagyi,这对您有帮助吗?还有问题吗?如果答案对您有帮助,请接受解决方案,其他人也可以从中受益。
  • 是的。就像对协方差的解释一样,它是有帮助的。谢谢你:)
  • 很高兴 :)
猜你喜欢
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2014-02-04
  • 1970-01-01
  • 2016-07-12
  • 1970-01-01
相关资源
最近更新 更多