C#泛型,抽象类和有界通配符

时间:2014-02-10 20:51:07

标签: c# generics

关于使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,但它告诉我只有委托和接口可以有协变类型参数。

那我怎么绕过这个泡菜?

2 个答案:

答案 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>>();
    }
}

这应该编译,但是如果不了解更多关于你的课程的话,很难说这是正确的