首页 > 解决方案 > Razor 中的 Html.DisplayNameFor List 与 IEnumerable

问题描述

我正在实现教程中的PaginatedList

有用。我的问题是,如果我在我的 Razor 页面中将其定义@modelIEnumerable,我可以这样做:

@model IEnumerable<CustomerDisplayViewModel>
@Html.DisplayNameFor(model => model.LastName)

如果我定义@modelList,则@Html.DisplayNameFor助手的工作方式不同,我必须这样称呼它:

@model List<CustomerDisplayViewModel>
@Html.DisplayNameFor(model => model.First().LastName)

区别在于,在第一次调用表达式 cast model 时CustomerDisplayViewModel,第二次调用是 a List<CustomerDisplayViewModel>

该问题是由编译器倾向于将调用转换为

Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> 
string DisplayNameFor<TResult>(Expression<Func<TModel, TResult>> expression);

代替

Microsoft.AspNetCore.Mvc.Rendering.HtmlHelperDisplayNameExtensions
public static string DisplayNameFor<TModelItem, TResult>(
this IHtmlHelper<IEnumerable<TModelItem>> htmlHelper, Expression<Func<TModelItem, TResult>> expression);

我知道我可以使用我的解决方法 ( @Html.DisplayNameFor( model => model.First().LastName)),但感觉不正确。

有没有办法进行调用或者生成我自己的调用 IEnumerable 扩展的扩展(我不希望从头开始创建扩展,这个调用应该与 IEnumerable 完全一样)。我可以使用 List<> 创建扩展方法,但是我无法转换它。

 public static string DisplayNameFor<TModelItem, TResult>
            (this Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<List<TModelItem>> htmlHelper,
            Expression<Func<TModelItem, TResult>> expression)
        {
            var castHelper = --- somehow cast helper to IHtmlHelper<IEnumerable<TModelItem>
            return castHelper.DisplayNameFor(expression);
        }

谢谢。

标签: c#asp.net-mvcasp.net-corerazor

解决方案


发生这种情况是因为的泛型参数TModel不是covariant。基本上,你不能这样做:IHtmlHelper

IHtmlHelper<List<CustomerDisplayViewModel>> helperList = new HtmlHelper<List<CustomerDisplayViewModel>(...);

IHtmlHelper<IEnumerable<CustomerDisplayViewModel>> helperIEnumerable = helperList;
// the above line is an error

但是,您可以这样做IEnumerable<T>

IEnumerable<int> intList = new List<int>();
IEnumerable<object> objList = intList; // no error

这是因为IEnumerable声明如下:

public interface IEnumerable<out T> : IEnumerable { .. }

请注意out指定泛型参数T是协变的关键字。已经IHtmlHelper<TModel>在框架中这样声明:

interface IHtmlHelper<out TModel> { .. }

你的代码会起作用的。


尽管如此,在这种情况下,您仍然可以使用Html.DisplayNameForInnerType()来获取显示名称(仅限 ASP.NET Core):

@model PaginatedList<CustomerDisplayViewModel>
...
@Html.DisplayNameForInnerType((CustomerDisplayViewModel c) => c.LastName)

请注意,您必须明确指定 lambda 表达式参数的类型。( CustomerDisplayViewModel c)。


推荐阅读