使用类型泛型时如何正确地将类转换为抽象类?

我有以下课程


public abstract class BaseViewPresenter { }

public abstract class BaseView<T> : UserControl

    where T : BaseViewPresenter { }


public class LoginPresenter : BaseViewPresenter { }

public partial class LoginView : BaseView<LoginPresenter> {  }

我有一个看起来像这样的方法(简化)


public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)

{

    var type = model.GetType();

    var viewType = _dataTemplates[type];


    // Correctly creates BaseView object

    var control = Activator.CreateInstance(viewType);


    // Fails to cast as BaseView<BaseViewPresenter> so returns null

    return control as BaseView<BaseViewPresenter>;

}

当我使用LoginPresenter实例调用此函数时


var login = new LoginPresenter();

var ctl = Resolve(login);

该行Activator.CreateInstance(viewType)正确解析为我的新实例LoginView,但是control as BaseView<BaseViewPresenter>无法正确进行强制转换,因此返回null。


有没有一种方法可以正确地强制control转换为BaseView<BaseViewPresenter>不使用特定类型的泛型?


由于LoginView继承自BaseView<LoginPresenter>和LoginPresenter继承BaseViewPresenter,我假设有一种方法可以转换LoginView为BaseView<BaseViewPresenter>。


我坚持使用.Net 3.5


月关宝盒
浏览 580回答 3
3回答

神不在的星期二

这是一个非常常见的问题。让我们重命名您的类型:abstract class Fruit { }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // was BaseViewPresenterabstract class FruitBowl<T> where T : Fruit // was BaseViewclass Apple : Fruit { }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// was LoginPresenterclass BowlOfApples : FruitBowl<Apple> {&nbsp; }&nbsp; // was LoginView您现在的问题是:我有一个BowlOfApples,继承自FruitBowl<Apple>。为什么不能将其用作FruitBowl<Fruit>?苹果是一种水果,所以一碗苹果是一碗水果。不,不是。您可以将香蕉放在一碗水果中,但是不能将香蕉放在一碗苹果中,因此,一碗苹果不是一碗水果。(并且通过类似的论点,一碗水果也不是一碗苹果。)由于您可以合法地对这两种类型执行的操作是不同的,所以它们是不兼容的。这是StackOverflow传奇人物Jon Skeet的照片,展示了这个事实:在此处输入图片说明所需的功能称为通用矛盾,当编译器可以证明差异是安全的,并且变化类型是引用类型时,只有接口和委托类型才支持该功能。例如,您可以IEnumerable<Apple>在IEnumerable<Fruit>需要的上下文中使用an ,因为编译器可以验证没有办法将a Banana放入一系列水果中。在此站点或网络上搜索“ C#协方差和逆方差”,您将找到有关此功能如何工作的更多详细信息。特别是,我有关如何在C#4中设计和实现此功能的系列文章从此处开始:http : //blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in -c-part-one.aspx

开心每一天1111

我接受了Eric的回答,因为它很好地解释了为什么无法实现我想要的东西,但是我还认为我会分享我的解决方案,以防其他人遇到同样的问题。我从原始BaseView类中删除了泛型类型参数,并创建了该类的第二个版本,BaseView其中包含了泛型类型参数及其详细信息。我的.Resolve()方法或其他不关心特定类型的代码使用第一个版本,而任何不关心特定类型的代码都使用第二个版本,例如BaseView这是我的代码最终看起来如何的示例// base classespublic abstract class BaseViewPresenter { }public abstract class BaseView : UserControl&nbsp;{&nbsp; &nbsp; public BaseViewPresenter Presenter { get; set; }}public abstract class BaseView<T> : BaseView&nbsp; &nbsp; where T : BaseViewPresenter{&nbsp; &nbsp; public new T Presenter&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; get { return base.Presenter as T; }&nbsp; &nbsp; &nbsp; &nbsp; set { base.Presenter = value; }&nbsp; &nbsp; }}// specific classespublic class LoginPresenter : BaseViewPresenter { }public partial class LoginView : BaseView<LoginPresenter>&nbsp;{&nbsp; &nbsp; &nbsp;// Can now call things like Presenter.LoginPresenterMethod()}// updated .Resolve method used for obtaining UI objectpublic BaseView Resolve(BaseViewPresenter presenter){&nbsp; &nbsp; var type = model.GetType();&nbsp; &nbsp; var viewType = _dataTemplates[type];&nbsp; &nbsp; BaseView view = Activator.CreateInstance(viewType) as BaseView;&nbsp; &nbsp; view.Presenter = presenter;&nbsp; &nbsp; return view;}
打开App,查看更多内容
随时随地看视频慕课网APP