如果类型参数约束指定了类型,为什么不能从用法中推断出类型参数?
Why type argument cannot be inferred from usage if type argument constraint specifies the type?
我创建了一个扩展方法,它应该为 table 提供 table header 文本,其中包含 collection 类型的项目 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>
这是之前向 C# 语言团队提出的请求:REQUEST: Pattern matching/better type inferencing with generics. #5023. However, note the linked comment, this introduces breaking changes, so is not currently implemented. See also 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)
进一步阅读:,参见 Jon Skeet 的回答。
我创建了一个扩展方法,它应该为 table 提供 table header 文本,其中包含 collection 类型的项目 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>
这是之前向 C# 语言团队提出的请求:REQUEST: Pattern matching/better type inferencing with generics. #5023. However, note the linked comment, this introduces breaking changes, so is not currently implemented. See also 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)
进一步阅读: