将泛型模型的子类传递给剃刀视图

lbs*_*str 12 asp.net oop razor asp.net-mvc-3

大图:

我发现了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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样的子类:

public class MyFooModel : BaseFooModel<MyBarType>
{
    // ...
}

public class MyBarType : BaseBarType
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我希望能够传递MyFooModel到这样定义的剃刀视图:

// FooView.cshtml
@model BaseFooModel<BaseBarType>
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用.我得到一个运行时错误,说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;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用该结构,以下工作可行:

new FooView<MyBarType>(new MyFooModel());
Run Code Online (Sandbox Code Playgroud)

我的问题:

我怎么能用Razor做到这一点?我怎样才能像我一样传递类型FooView
我不能,但有什么方法可以解决这个问题吗?我能以某种方式实现相同的架构吗?

如果我能提供更多信息,请告诉我.我正在使用.NET 4和MVC 3.


编辑:
目前,我只是为每个子类添加一个剃刀视图BaseFooModel<BaseBarType>.我对此并不感到兴奋,因为每次添加新模型时我都不想创建新视图.

另一种选择是只取的事实,我的优势能够得到正规的C#类这方面的工作没有剃须刀.我可以让我的剃刀查看@inheritsc#视图,然后调用一些渲染方法.我不喜欢这个选项,因为我不喜欢有两种渲染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
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

结束了什么:

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
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*ale 19

您需要在类层次结构中引入一个带有协变泛型类型参数的接口:

public interface IFooModel<out T> where T : BaseBarType
{
}
Run Code Online (Sandbox Code Playgroud)

并从上面的接口派生您的BaseFooModel.

public abstract class BaseFooModel<T> : IFooModel<T> where T : BaseBarType
{
}
Run Code Online (Sandbox Code Playgroud)

在你的控制器中:

[HttpGet]
public ActionResult Index()
{
    return View(new MyFooModel());
}
Run Code Online (Sandbox Code Playgroud)

最后,将视图的模型参数更新为:

@model IFooModel<BaseBarType>
Run Code Online (Sandbox Code Playgroud)