大图:
我发现看起来像是剃刀的限制,我有麻烦想出一个很好的方法.
玩家们:
假设我有一个这样的模型:
public abstract class BaseFooModel<T> where T : BaseBarType { public abstract string Title { get; } // ACCESSED BY VIEW public abstract Table<T> BuildTable(); protected Table<T> _Table; public Table<T> Table // ACCESSED BY VIEW { get { if (_Table == null) { _Table = BuildTable(); } return _Table; } } }
还有一个这样的子类:
public class MyFooModel : BaseFooModel<MyBarType> { // ... } public class MyBarType : BaseBarType { // ... }
我想要能够将MyFooModel传递到如下定义的剃刀视图中:
// FooView.cshtml @model BaseFooModel<BaseBarType>
但是,这不行.我收到一个运行时错误,说FooView期望BaseFooModel< BaseBarType>但得到MyFooModel.回想一下,来自BaseFooModel&MyBarType>的inits中的MyFooModel而MyBarType继承自BaseBarType.
我试过了
我在非剃刀的土地上试了一下,看看是否也是这样.我不得不在视图中使用模板参数来使其工作.这是非剃刀视图:
public class FooView<T> where T : BaseBarType { BaseFooModel<T> Model; public FooView(BaseFooModel<T> model) { Model = model; } }
有了这个结构,下面的工作:
new FooView<MyBarType>(new MyFooModel());
我的问题:
如何用剃须刀做这个?如何传递类似我正在做的FooView?
我不能,但有什么办法吗?我可以以某种方式实现相同的架构吗?
让我知道如果我能提供更多的信息.我正在使用.NET 4和MVC 3.
编辑:
现在,我只是为BaseFooModel< BaseBarType>的每个子类添加一个剃刀视图.我不是很高兴,因为我不想每次添加新的模型时都要创建一个新的视图.
另一个选择是利用这样一个事实,我能够在没有剃刀的普通c#类中得到这个工作.我可以让我的剃须刀视图@继承c#视图,然后调用一些渲染方法.我不喜欢这个选项,因为我不喜欢有两种渲染HTML的方式.
任何其他想法?当我用Foo和Bar提供类名时,我很难理解问题的上下文,但是由于它有点敏感,我无法提供太多的信息.我对此道歉.
我到目前为止,使用本杰明的答案:
public interface IFooModel<out T> where T : BaseBarModel { string Title { get; } Table<T> Table { get; } // this causes an error: // Invalid variance: The type parameter 'T' must be // invariantly valid on IFooModel<T>.Table. // 'T' is covariant. } public abstract class BaseFooModel<T> : IFooModel<T> where T : BaseBarModel { // ... }
最后工作:
public interface IFooModel<out T> where T : BaseBarModel { string Title { get; } BaseModule Table { get; } // Table<T> inherits from BaseModule // And I only need methods from BaseModule // in my view. } public abstract class BaseFooModel<T> : IFooModel<T> where T : BaseBarModel { // ... }
解决方法
您需要在类层次结构中引入一个具有
covariant通用类型参数的接口:
public interface IFooModel<out T> where T : BaseBarType { }
并从上述界面派生您的BaseFooModel.
public abstract class BaseFooModel<T> : IFooModel<T> where T : BaseBarType { }
在你的控制器中:
[HttpGet] public ActionResult Index() { return View(new MyFooModel()); }
最后,将视图的模型参数更新为:
@model IFooModel<BaseBarType>