Asp.net

將通用模型的子類傳遞給剃刀視圖

  • April 1, 2013

大圖:

我發現了 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# 類中使用它。我可以讓我的剃刀查看@inheritsc# 視圖,然後呼叫一些渲染方法。我不喜歡這個選項,因為我不喜歡有兩種呈現 html 的方式。

還有其他想法嗎?我知道當我用Fooand給出類名時很難理解問題的上下文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
{
   // ...
}

您需要在類層次結構中引入一個帶有協變泛型類型參數的介面:

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>

在 ASP.NET MVC 2 和 MVC 3 之間使用基於介面的模型是故意改變的。

你可以在這裡看到

MVC 團隊:

我們不鼓勵使用基於介面的模型(考慮到錯誤修復所施加的限制,我們也不可以實際支持)。切換到抽象基類可以解決這個問題。

《斯科特·漢塞爾曼》

引用自:https://stackoverflow.com/questions/15646812