【发布时间】:2013-06-17 04:11:42
【问题描述】:
我在 IQueryable 上编写了一个扩展方法,它返回相同类型的 IQueryable,只是过滤了一下。 假设它是这样的:
public static IEnumerable<T> Foo<T>(this IEnumerable<T> source, int? howmany = null)
{
if (howmany.HasValue)
return source.Take(howmany.Value);
return source;
}
调用上述方法就像someLinqResult.Foo(2)一样简单
我需要其他方法来返回其他泛型类的实例,但使用其他基类(与上面的源T 不同)。
所以,这里是代码,让我们假设这个方法应该返回一个给定类型的列表(除了 IQueryable 具有的输入类型!)但长度相同[实际问题是关于转换 NHibernate 查询结果,但它没有问题):
public static List<TTarget> Bar<TTarget,TSource>(this IEnumerable<TSource> source)
{
return new List<TTarget>(source.Count());
}
现在,鉴于strLinqResult 是IQueryable<string>,我需要将其命名为strLinqResult.Bar<int,string>();。
重点是我必须传递这两种类型,即使第一种类型已经知道,因为我正在调用已经定义的IQuerable 上的方法。
既然调用 Foo(2) 和 not Foo<string>(2) 就足够了,我认为编译器能够自动“传递/猜测”类型。
那么为什么我需要调用第二种方法Bar<int,string>(); 而不仅仅是Bar<int>()?
实际代码:
public static ListResponse<TResponse>
BuildListResponse<T,TResponse>(this IQueryable<T> iq, ListRequest request)
where TResponse: new()
{
var result = iq.ApplyListRequestParams(request).ToList().ConvertAll(x => x.TranslateTo<TResponse>());
var tcount = iq.Count();
return new ListResponse<TResponse> {
Items = result,
_TotalCount = tcount,
_PageNumber = request._PageNumber ?? 1,
};
}
ApplyListRequestParams 是示例代码中的一种 Foo 方法 - 它只是应用 ListRequest 对象中可用的分页和排序参数。
Items 是 public List<T> Items 中的 class ListResponse<T>。
TranslateTo 是 ServiceStack 中的一个方法。
上面调用 NHibernate(T 是域模型)返回的 IQueryable<T> 的方法获取请求参数(排序、分页),应用它们,然后将结果列表从 DomainModel 转换为类型为 @987654343 的 DTO 对象@。然后将该列表包装在一个通用响应类中(通用,因此它可用于许多 DTO 类型)
【问题讨论】:
-
您是否尝试过将定义切换为
Bar<TSource, TTarget>(...)? -
@PinnyM 是的,我做到了。它仍然说我需要传递 2 个类型参数
-
@Jon 我可能误解了其他解决方案,但扩展实际类是不可能的 - 它需要是扩展方法!
-
@migajek:链接的答案建议在单独的泛型类(不是您正在使用的类)上使用静态方法。或者,您可以安排使用中间类型使用扩展方法语法进行调用,但这需要 两个 扩展方法调用。仅通过一次调用使用扩展方法语法要求编译器仅推断类型参数之一,而它不会这样做。
-
假设您添加了
Bar<TSource>(this IEnumerable<TSource> source)。如果编译器接受了您的速记,那么现在strLinqResult.Bar<string>();是指Bar<string>还是Bar<string, string>将是明确的。我认为这就是 Johny Skovdal 在他的回答中的意思,但我想把它拼出来。
标签: c# generics extension-methods