关于使Generics在C#中工作,我遇到了一些问题:
我有以下课程:
public abstract class OphControl<TDataModel> : Control
where TDataModel : OphDataModel, new()
{
/// <summary>
/// The data model for this control.
/// </summary>
public TDataModel DataModel { get; private set; }
public IEnumerable<OphControl<OphDataModel>> OphControls {
get {
return Controls.Cast<Control>().Where(control => control is OphControl<OphDataModel>).Cast<OphControl<OphDataModel>>();
}
}
protected OphControl() {
DataModel = new TDataModel();
}
}
我的问题是,OphControls
属性将无法编译,因为OphDataModel
是抽象的,因此我认为在编译时无法确定OphDataModel是否具有零参数公共构造函数(注意new()
上的TDataModel
约束。
我甚至不确定这是否是正确的方法。我真正想要的东西就像来自Java的OphControl<? extends OphDataModel>
。我尝试在类声明中向out
添加TDataModel
,但它告诉我只有委托和接口可以有协变类型参数。
那我怎么绕过这个泡菜?
答案 0 :(得分:1)
以下是一些混乱的事情。首先,OphControl<TDataModel>
并非来自OphControl<OphDataModel>
,而您对out
关键字(协方差/逆变)是正确的,它们只能与代理和接口一起使用。由于它不是基类,您可能无法投射它。
与java不同,c#不支持通用通配符(...<? extends ...>
)。解决方法是创建非泛型版本并使其成为基类。
public abstract class OphControl : Control { ... }
public abstract class OphControl<TDataModel> : OphControl
where TDataModel : OphDataModel, new() { ... }
不幸的是,基类不能具有DataModel属性,因为c#也不支持协变返回类型。
至少你可以拥有
public IEnumerable<OphControl> OphControls {
get {
return Controls.OfType<OphControl>();
}
}
答案 1 :(得分:0)
我只需更改OphControls
上的通用参数:
public IEnumerable<OphControl<TDataModel>> OphControls {
get {
return Controls.Cast<Control>().Where(control => control is OphControl<TDataModel>).Cast<OphControl<TDataModel>>();
}
}
这应该编译,但是如果不了解更多关于你的课程的话,很难说这是正确的