【问题标题】:Asp.Net MVC Cast Model in view视图中的 Asp.Net MVC Cast 模型
【发布时间】:2021-01-05 10:39:20
【问题描述】:

我有三个模型:动物、狗和猫。

类动物

public class Animal
{
    
}

类狗

public class Dog : Animal
{
    
}

还有类猫

public class Dog : Animal
{
    
}

还有两个控制器(DogController 和 CatController),每个控制器中都有一个 index 动作返回视图以显示列表结果。

狗控制器

public class DogController : Controller
{
   public DogController ()
   {       
   }
   public async Task<IActionResult> Index()
   { 
      DogRepository IRepos = new DogRepository ();
      // Get List of Dogs
      IList<Animal> listDogs= await IRepos.GetListDogs();            
      return View(ilIst);
   } 

   [Httpost]
   public async Task<IActionResult> Add(Animal Dog)
   { 
      ....
      // Add dog to Database
                  
      return RedirectToAction("Index");
   } 


}

狗的索引视图

@model IEnumerable<Dog> 

@{
    ViewData["Title"] = "Index";
}
<div class="row">
    <div class="table-responsive">
        <table class="table">           
            </thead>
            <tbody>
                @foreach (var item in Model)
                {
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.Dog_ID)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Dog_Name)
                        </td>
                    </tr>
                }
        </table>
    </div>
</div>

在Dog Controller的索引Action中,返回类型为IList&lt;Animal&gt;,索引视图中的模型类型为IEnumerable&lt;Dog&gt;。 应用程序执行时,会产生错误

处理请求时发生未处理的异常。 InvalidOperationException:传递到 ViewDataDictionary 的模型项的类型为“System.Collections.Generic.List1[Animal]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable1[Dog]”。

因此,将控制器中的动作发送的动物列表转换为视图中模型的狗类型列表非常重要。 我们如何将动物列表转换为视图中的狗列表,@model IEnumerable as IEnumerable 不起作用。

在post action中也是一样的,我们如何将Dog模型从view中投射到action中的Animal模型中

【问题讨论】:

  • 为什么listDogsIList&lt;Animal&gt; 而不是IList&lt;Dog&gt;?你不应该改变那个变量的类型吗?
  • 除了上面的正确答案之外,我看到您正在使用一个名为 DogRepository 的额外类来包含您的逻辑。不要称它为 IRepos,这是你要给你的接口起的名字。考虑将其更改为类似 Repository 这样您就可以使代码通用并实例化为例如存储库。您可以将此部分作为“Scoped”服务的一部分,并通过依赖注入将其添加到控制器中,这是一种避免重复代码的非常巧妙的方法。
  • 这是对象多态性。我想使用父类来声明一个对象,然后我可以将子类的任何对象分配给它。例如,它可以用于接受参数的函数。参数可以是父类类型,所以我们可以向这个函数发送子类的任何对象。这是我的示例的情况,我声明了 Aimal 类型的对象,因此我可以为该对象分配 Dog 或 Cat。现在的问题是如何将这个 Animal 类型的对象发送到接受 Dog 和 Cat 类型的 Model 的视图。它会产生错误
  • 问题在于您的 Dogs 视图中的模型比您发送给它的集合类型更具体。如果您在视图中更改为 ,它将接受狗或猫的集合,但模型将仅识别基类型中的字段,这可能不是您想要的。为狗或猫提供特定视图并没有错,但您需要从控制器传递特定集合。另外,请考虑传递 DTO 而不是实际的数据库类型;)
  • 绝对,我认为多态性是从子类到母类而不是从母类到子类。效果我必须将模型与 Animal 类型一起发送给它一个 Dog 或 cat 对象

标签: c# asp.net-mvc asp.net-core asp.net-mvc-4 asp.net-mvc-3


【解决方案1】:

多态性似乎不适用于页面模型。您可以为 Cat 和 Dog 定义局部视图,并为局部视图使用子类,并使用基类作为主视图的模型。

主视图(索引):

@model IEnumerable<Animal>

@{
    ViewData["Title"] = "Index";
}

<div class="row">
    <div class="table-responsive">
        <table class="table">
            <thead>
            </thead>
            <tbody>
                @foreach (var item in Model)
                {
                    @if (item is Dog)
                    {
                        <partial name="_DogPartial" model="item" />
                    }
                }
        </table>
    </div>
</div>

局部视图 (_DogPartial):

@model Dog
<tr>
    <td>
        @Html.DisplayFor(modelItem => Model.Dog_ID)
    </td>
    <td>
        @Html.DisplayFor(modelItem => Model.Dog_Name)
    </td>
</tr>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    相关资源
    最近更新 更多