我对IEumerable接口上的扩展方法有一个有趣的需求 - 与List.ConvertAll相同。这已在here之前完成,我找到了一个解决方案here。我不喜欢这个解决方案是他构建一个List来保存转换后的对象,然后返回它。我怀疑他在撰写文章时没有LINQ,所以我的实现就是:
public static class IEnumerableExtension
{
public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Func<T, TOutput> converter)
{
if (null == converter)
throw new ArgumentNullException("converter");
return from item in collection
select converter(item);
}
}
我更喜欢这个是我无需加载任何TOutput的整个列表即可“转换”。请注意,我还更改了委托的类型 - 从Converter到Func。编译是一样的,但我认为这使我的意图更清晰 - 我不是故意这只是类型转换。
这引出了我的问题:在我的存储库层中,我有很多查询返回ID的列表 - 实体的ID。我曾经有过几个类,它们以各种方式将这些ID“转换”为实体。使用这种扩展方法,我可以将所有这些扩展到代码,如下所示:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.ConvertAll<Part>(PartRepository.Find);
}
其中'converter'实际上是存储库的Find-by-ID方法。就我而言,'转换器'可能会做很多事情。有没有人看到这种方法有任何问题?
答案 0 :(得分:10)
我用这种方法看到的主要问题是完全没必要。
您的ConvertAll
方法与Enumerable.Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>)
没什么区别,后者是标准的LINQ运算符。没有理由为已经在框架中的东西编写扩展方法。
你可以这样做:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.Select<int,Part>(PartRepository.Find);
}
注意:您的方法也需要<int,Part>
进行编译,除非PartRepository.Find
仅适用于int,并且只返回Part实例。如果你想避免这种情况,你可以这样做:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.Select(i => PartRepository.Find<Part>(i)); // I'm assuming that fits your "Find" syntax...
}
答案 1 :(得分:1)
为什么不使用yield
关键字(并且只根据需要转换每个项目)?
public static class IEnumerableExtension
{
public static IEnumerable<TOutput> ConvertAll<T, TOutput>
(this IEnumerable<T> collection, Func<T, TOutput> converter)
{
if(null == converter)
throw new ArgumentNullException("converter");
foreach(T item in collection)
yield return converter(item);
}
}