【发布时间】:2013-03-26 20:31:51
【问题描述】:
大局:
我发现了 Razor 的一个限制,我无法想出一个好的解决方法。
玩家:
假设我有一个这样的模型:
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。回想一下 MyFooModel 继承自 BaseFooModel<MyBarType> 和 MyBarType 继承自 BaseBarType。
我尝试过的:
我在非剃须刀的土地上尝试过这个,看看是否同样如此,确实如此。我必须在视图中使用模板参数才能使其工作。这是非剃刀观点:
public class FooView<T>
where T : BaseBarType
{
BaseFooModel<T> Model;
public FooView(BaseFooModel<T> model)
{
Model = model;
}
}
使用该结构,以下确实有效:
new FooView<MyBarType>(new MyFooModel());
我的问题:
我怎样才能用 Razor 做到这一点?我怎样才能像使用 FooView 一样传递一个类型?
我不能,但是有没有办法解决?我能以某种方式实现相同的架构吗?
如果我能提供更多信息,请告诉我。我正在使用 .NET 4 和 MVC 3。
编辑:
现在,我只是为BaseFooModel<BaseBarType> 的每个子类添加一个剃刀视图。我对此并不感到兴奋,因为我不想每次添加新模型时都必须创建新视图。
另一种选择是利用我 能够在没有剃刀的常规 c# 类中使其正常工作这一事实。我可以让我的剃刀视图@inherits 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
{
// ...
}
【问题讨论】:
-
我经常在输入问题时或至少在不久之后找到答案。这次不是……
-
你的 BaseFooModel 是什么 - 它在页面上做了什么(插入、只是查看、是否更改等)?这是相关的(一些示例代码)
-
这是一个很好的观点,但我会争辩说,由于此信息正在用于视图中,因此它应该只被读取。任何更新都应该在控制器操作方法中进行。
-
@NSGaga 回答您的问题,请参阅上面的本杰明评论。他是对的。只是子类必须实现的一些 getter 和方法。
-
@Benjamin 您的评论甚至更好:) 我认为(有道理)-答案值得赏金-但我正在寻找我们是否可以改进这一点。即细节与“差异”完全不同。
IEnumerable<Record>适用于简单的情况(当然没有“标题”等)。如果基本接口必须支持任何东西 - 或者通过 js 或其他东西 - 那么这可能会失败。
标签: asp.net asp.net-mvc-3 oop razor