【问题标题】:Dynamically Assign Concrete Class That Extends Abstract Class With Generic动态分配用泛型扩展抽象类的具体类
【发布时间】:2017-07-30 03:02:02
【问题描述】:

我有以下类定义

public class AbstractIem<T> where T : SomeObject 
{ 
    public abstract T Item { get; }
}

public class ConcreteItem1 : AbstractItem<ClassExtendingSomeObject>
{
    public override ClassExtendingSomeObject Item { get; }
}

public class ConcreteItem2 : AbstractItem<AnotherClassExtendingSomeObject> 
{
    public override ClassExtendingSomeObject Item { get; }
}

我遇到问题的地方是当我想动态分配AbstractItem&lt;SomeObject&gt;的对象时,

AbstractItem<SomeObject> myItem;

switch (someIntValue) 
{
    case 1:
        myItem = new ConcreteItem1();
        break;
    case 2:
        myItem = new ConcreteItem2();
        break;
}

尝试设置myItem时出现以下错误:

无法将类型“ConcreteItem1”隐式转换为“AbstractItem”

我认为这应该可以工作,因为每个ConcreteItem 类都扩展了AbstractItem&lt;SomeObject&gt;,其中SomeObject 是一个具体类型。

【问题讨论】:

    标签: c# generics inheritance


    【解决方案1】:

    您正在尝试做的事情称为变体,在 C# 中它只能在接口上实现。因此,要使其工作,您必须将AbstractItem&lt;T&gt; 更改为接口并将T 标记为协变。

    public interface IItem<out T> where T : SomeObject
    {
        T Item { get; }
    }
    
    public class ConcreteItem1 : IItem<ClassExtendingSomeObject>
    {
        public ClassExtendingSomeObject Item { get; }
    }
    
    public class ConcreteItem2 : IItem<AnotherClassExtendingSomeObject>
    {
        public AnotherClassExtendingSomeObject Item { get; }
    }
    

    注意在IItem的声明中T前面添加了out关键字。

    使用该设置,以下代码可以按预期工作:

    IItem<SomeObject> myItem;
    
    switch (someIntValue)
    {
        case 1:
            myItem = new ConcreteItem1();
            break;
        case 2:
            myItem = new ConcreteItem2();
            break;
    }
    

    有关 .NET 中协变和逆变的更多信息,请参阅 docs.microsoft.com 上的Covariance and Contravariance in Generics

    【讨论】:

    • 非常有趣。我以前从未听说过方差。是否有特定原因只能在接口上完成?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    相关资源
    最近更新 更多