C# 为什么在IEnumerables上使用标准扩展方法
当我在列表上使用标准扩展方法时,例如 其中(…) 结果总是IEnumerable,并且 您决定执行列表操作,例如Foreach() 我们需要Cast(不漂亮)或使用ToList()扩展方法 (可能)使用消耗更多内存的新列表(是这样吗?) 或C# 为什么在IEnumerables上使用标准扩展方法,c#,visual-studio,linq,extension-methods,C#,Visual Studio,Linq,Extension Methods,当我在列表上使用标准扩展方法时,例如 其中(…) 结果总是IEnumerable,并且 您决定执行列表操作,例如Foreach() 我们需要Cast(不漂亮)或使用ToList()扩展方法 (可能)使用消耗更多内存的新列表(是这样吗?) 或 如果要在列表上创建一个简单的foreach,可以执行以下操作: foreach (var item in myList.Where([Where clause])) { // Do something with each item. } 如果要在列
如果要在列表上创建一个简单的foreach,可以执行以下操作:
foreach (var item in myList.Where([Where clause]))
{
// Do something with each item.
}
如果要在列表上创建一个简单的foreach,可以执行以下操作:
foreach (var item in myList.Where([Where clause]))
{
// Do something with each item.
}
as
绝对不是一个好方法,如果它能起作用,我会感到惊讶
关于什么是“最好的”,我建议用foreach
而不是foreach
:
foreach(var item in myList.Where(p=>p.Length>5)) {
... // do something with item
}
如果您非常想使用列表方法,可能:
myList.FindAll(p=>p.Length>5).ForEach(...);
或者确实
var result = myList.FindAll(p=>p.Length>5).BinarySearch(...);
但请注意,这确实(与第一个不同)需要额外的数据副本,如果myList
中有100000个长度超过5的项目,这可能会很麻烦
LINQ返回IEnumerable
的原因是它(LINQ到对象)被设计为可组合和流式处理,如果您转到列表,这是不可能的。例如,几个的组合,其中
/选择
等应该不严格地需要创建大量中间列表(实际上,LINQ不需要)
当你认为不是所有的序列都有界时,这更重要;有无限个序列,例如:
static IEnumerable<int> GetForever() {
while(true) yield return 42;
}
var thisWorks = GetForever().Take(10).ToList();
静态IEnumerable GetForever(){
而(真实)收益率为42;
}
var thisWorks=GetForever().Take(10.ToList();
直到
ToList
它正在组成迭代器,才生成中间列表。不过,有一些缓冲操作,如OrderBy
,需要先读取所有数据。大多数LINQ操作都是流式的。作为的绝对不是一个好方法,如果它能工作,我会感到惊讶
关于什么是“最好的”,我建议用foreach
而不是foreach
:
foreach(var item in myList.Where(p=>p.Length>5)) {
... // do something with item
}
如果您非常想使用列表方法,可能:
myList.FindAll(p=>p.Length>5).ForEach(...);
或者确实
var result = myList.FindAll(p=>p.Length>5).BinarySearch(...);
但请注意,这确实(与第一个不同)需要额外的数据副本,如果myList
中有100000个长度超过5的项目,这可能会很麻烦
LINQ返回IEnumerable
的原因是它(LINQ到对象)被设计为可组合和流式处理,如果您转到列表,这是不可能的。例如,几个的组合,其中
/选择
等应该不严格地需要创建大量中间列表(实际上,LINQ不需要)
当你认为不是所有的序列都有界时,这更重要;有无限个序列,例如:
static IEnumerable<int> GetForever() {
while(true) yield return 42;
}
var thisWorks = GetForever().Take(10).ToList();
静态IEnumerable GetForever(){
而(真实)收益率为42;
}
var thisWorks=GetForever().Take(10.ToList();
直到ToList
它正在组成迭代器,才生成中间列表。不过,有一些缓冲操作,如OrderBy
,需要先读取所有数据。大多数LINQ操作都是流操作。您不能将(转换为)IEnumerable
转换为列表<代码>IEnumerable
在访问项目时对其求值。调用ToList()
将枚举集合中的所有项并返回一个新列表,这会导致内存效率低下,而且是不必要的。如果您愿意对任何集合使用ForEach
扩展方法,那么最好编写一个新的ForEach
扩展方法,用于任何集合
public static void ForEach<T>(this IEnumerable<T> enumerableList, Action<T> action)
{
foreach(T item in enumerableList)
{
action(item);
}
}
公共静态void ForEach(此IEnumerable enumerableList,Action)
{
foreach(枚举列表中的T项)
{
行动(项目);
}
}
您不能将(转换为)IEnumerable
转换为列表
<代码>IEnumerable
在访问项目时对其求值。调用ToList()
将枚举集合中的所有项并返回一个新列表,这会导致内存效率低下,而且是不必要的。如果您愿意对任何集合使用ForEach
扩展方法,那么最好编写一个新的ForEach
扩展方法,用于任何集合
public static void ForEach<T>(this IEnumerable<T> enumerableList, Action<T> action)
{
foreach(T item in enumerableList)
{
action(item);
}
}
公共静态void ForEach(此IEnumerable enumerableList,Action)
{
foreach(枚举列表中的T项)
{
行动(项目);
}
}
其中一个方法是允许对任何受支持的数据类型进行组合查询,这是通过使用通用接口而不是具体类(如您提到的IEnumerable
)指定返回类型来实现的。这允许根据需要将螺母和螺栓实现为具体类(例如,whereEnumerableInterator
或提升到SQL查询中),或使用方便的yield
关键字
此外,还有一个问题。基本上,在实际使用查询之前,没有真正的工作完成。这使得可能非常昂贵的()操作只能完全根据需要完成
如果List.Where
返回另一个List
,则可能会限制合成,并肯定会阻碍延迟执行(更不用说生成多余内存)
因此,回顾一下您的示例,使用Where
运算符的结果的最佳方法取决于您想对其执行什么操作
// This assumes myList has 20,000 entries
// if .Where returned a new list we'd potentially double our memory!
var largeStrings = myList.Where(ss => ss.Length > 100);
foreach (var item in largeStrings)
{
someContainer.Add(item);
}
// or if we supported an IEnumerable<T>
someContainer.AddRange(myList.Where(ss => ss.Length > 100));
//假设myList有20000个条目
//如果.Where返回一个新列表,我们的内存可能会翻倍!
var largeStrings=myList.Where(ss=>ss.Length>100);
foreach(最大字符串中的var项目)