3 回答
TA贡献1963条经验 获得超6个赞
这是一个非常常见的问题。让我们重命名您的类型:
abstract class Fruit { } // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // 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
TA贡献1836条经验 获得超13个赞
我接受了Eric的回答,因为它很好地解释了为什么无法实现我想要的东西,但是我还认为我会分享我的解决方案,以防其他人遇到同样的问题。
我从原始BaseView类中删除了泛型类型参数,并创建了该类的第二个版本,BaseView其中包含了泛型类型参数及其详细信息。
我的.Resolve()方法或其他不关心特定类型的代码使用第一个版本,而任何不关心特定类型的代码都使用第二个版本,例如BaseView
这是我的代码最终看起来如何的示例
// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl
{
public BaseViewPresenter Presenter { get; set; }
}
public abstract class BaseView<T> : BaseView
where T : BaseViewPresenter
{
public new T Presenter
{
get { return base.Presenter as T; }
set { base.Presenter = value; }
}
}
// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter>
{
// Can now call things like Presenter.LoginPresenterMethod()
}
// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
BaseView view = Activator.CreateInstance(viewType) as BaseView;
view.Presenter = presenter;
return view;
}
- 3 回答
- 0 关注
- 619 浏览
添加回答
举报