如何将子类分配给非泛型类中的泛型字段

本文关键字:泛型类 泛型 字段 子类 分配 | 更新日期: 2023-09-27 18:25:20

在C#中,我试图将一个私有泛型变量存储在通过泛型方法传入的非泛型类中。泛型方法应该接受向上转换为基类类型的子类。

这是一个问题的例子:

class BaseModel { }
class DerivedModel : BaseModel { }
class Data<T> where T : BaseModel { }
// Class is NOT generic
class DataConsumer
{
    // How do I set this to generic?
    private Data<BaseModel> data;
    public void Set<T>(Data<T> data) where T : BaseModel
    {
        // Compile time error: 
        // Cannot convert source type 'Generic.Data<T> 
        // to target type 'Generic.Data<Generic.BaseModel>'
        this.data = data;
    }
}

如何将子类分配给非泛型类中的泛型字段

这是因为您试图将更派生的类型Data<T>分配给基类型Data<BaseModel>,这在泛型类中是不允许的。

你有两个选择:

1-使DataConsumer通用:

class DataConsumer<T> where T : BaseModel
{
    private Data<T> data;
    public void Set(Data<T> data)
    {
        this.data = data;
    }
}

2-OR,使Data成为接口而不是类,并使用out关键字将T标记为协变类型:

interface IData<out T> where T : BaseModel { }
class DataConsumer
{
    private IData<BaseModel> data;
    public void Set<T>(IData<T> data) where T : BaseModel
    {
        this.data = data;
    }
}

阅读更多关于Generics中协方差和反方差的信息,点击此处

this.data属于Data<BaseModel>类型,而函数参数data属于Data<T : BaseModel>类型。

您的示例一开始就有点违背了泛型的全部目的,但您可以将Set()方法声明为非泛型方法,并强制客户端执行强制转换。

private Data<BaseModel> data;
public void Set(Data<BaseModel> data)
{
  this.data = data;
}

顺便说一句,如果您声明所有涉及的实体都是泛型的,那么约束将只允许您通过BaseModel的契约来操作对象,所以我看不出显式强制转换是必要的。