我创建了一个扩展方法,该方法应该为包含IList<T>
类型的项目的表提供表标题文本。虽然,编译器说无法从用法中推断出TModel,但是对我来说,很明显,如果类型参数约束指出TListModel
是IList<TModel>
,那么就可以推断出TModel
public static MvcHtmlString HeaderFor<TListModel, TModel, TValue>(this HtmlHelper<TListModel> listViewModel, Expression<Func<TModel, TValue>> expression)
where TListModel : IList<TModel>
TListModel
是List<Product>
,所以TModel
是Product
,因此,我想像这样使用HtmlHelper:
<th scope="col" class="azonosito">
@Html.HeaderFor(x => x.Price)
</th>
我现在必须像这样使用它,这很尴尬:
<th scope="col" class="azonosito">
@Html.HeaderFor((Product x) => x.Price)
</th>
答案 0 :(得分:2)
这是先前向C#语言团队提出的请求:REQUEST: Pattern matching/better type inferencing with generics. #5023。但是,请注意链接的注释,这会引入重大更改,因此当前未实现。另请参见https://github.com/dotnet/roslyn/issues/11242。
问题在于,编译器无法推断TListModel
的类型只能是IList<TModel>
。它不了解列表的成员(IList<TModel>
)和容器(TListModel
)之间没有联系。
有几种方法可以解决此问题。正如您发现的那样,一种方法是显式地为lambda提供类型,尽管您也可以显式地提供类型参数:@{Html.HeaderFor<IList<SomeModel>, SomeModel, int>(x => x.Price)}
。
对于实际的解决方案,您可以更改扩展方法定义。此更改应将成员类型作为扩展方法的参数的一部分提供。
public static MvcHtmlString HeaderFor<TModel, TValue>(this HtmlHelper<IList<TModel>> listViewModel, Expression<Func<TModel, TValue>> expression)
{
return new MvcHtmlString("a");
}
这允许隐式类型推断而没有编译器错误:
@model IList<SomeModel>
...
@Html.HeaderFor(x => x.Price)
进一步阅读:How can I return <TEnumerable, T> : where TEnumerable:IEnumerable<T>,请参阅乔恩·斯基特(Jon Skeet)的答案。