在列表<>上选择和ForEach
这个问题在这里已经有了答案:
我们从这里开始:
我有一个对象列表。
理解这一点非常重要,尽管准确,但这种说法让ac#程序员想要更多。 什么样的对象? 在.Net世界中,始终牢记您正在使用的特定类型的对象是值得的。 在这种情况下,该类型是UserProfile
。 这可能看起来像是一个侧面问题,但它会很快与具体问题变得更相关。 你想说的是这样的:
我有一个UserProfile对象的列表。
现在我们来看看你的两个表达式:
users.Where(i => i.UserName ==“”)。ToList()。ForEach(i => i.UserName =“NA”);
和
users.Where(i => i.UserName ==“”)。ForEach(i => i.UserName =“NA”);
除了只有第一次编译或工作之外,区别在于您需要调用.ToList()
将Where()
函数的结果转换为List类型。 现在我们开始明白为什么当你使用.Net代码的时候,你总是想用类型来思考,因为现在你应该想到:“那么我在用什么类型?” 我很高兴你问。
.Where()
函数产生一个IEnumerable<T>
类型,实际上它本身并不是一个完整的类型。 这是一个介绍某种东西的接口,它实现了契约所能实现的类型。 IEnumerable接口起初可能会让人困惑,但要记住的重要一点是它定义了可以用于foreach
循环的一些东西。 这是唯一的目的。 .Net中的任何东西都可以用于foreach循环:数组,列表,集合 - 它们几乎都实现了IEnumerable接口。 还有其他的东西可以循环使用。 例如,字符串。 您现在需要使用List或Array作为参数的许多方法可以通过将该参数类型更改为IEnumerable来变得更加强大和灵活。
.Net还可以很容易地创建与这个接口一起工作的基于状态机的迭代器。 这对于创建本身不包含任何项目的对象特别有用,但确实知道如何以特定方式循环显示不同集合中的项目。 例如,我可能会将大小为20的数组中的项目3到12循环。或者可能会按照字母顺序遍历项目。 这里重要的是我可以做到这一点,而不需要复制或复制原件。 这使得它在内存方面非常高效,并且它的结构使得您可以轻松地组合不同的迭代器来获得非常强大的结果。
IEnumerable<T>
类型特别重要,因为它是构成linq系统核心的两种类型之一(另一种是IQueryable)。 大多数可以使用的.Where()
.Select()
.Any()
等linq运算符都被定义为IEnumerable的扩展。
但是现在我们ForEach()
一个例外: ForEach()
。 此方法不是IEnumerable的一部分。 它被直接定义为List<T>
类型的一部分。 因此,我们再次看到,了解您始终使用的是什么类型,包括构成完整声明的每个不同表达式的结果都很重要。
这也是为什么这个特定的方法不是直接的IEnumerable的一部分。 我相信答案在于linq系统从功能编程世界吸取了很多灵感。 在函数式编程中,您希望具有完成一件事的操作(函数),而没有副作用。 理想情况下,这些函数不会改变原始数据,而是会返回新的数据。 ForEach()
方法隐含地关于创建改变数据的不良副作用。 这只是不好的功能风格。 此外,ForEach()打破方法链接,因为它不返回新的IEnumerable。
在这里学习还有一个教训。 让我们来看看你的原始片段:
List<UserProfile> users = new List<UserProfile>();
// ..load users with list of users
List<UserProfile> selecteditem = users.Where(i => i.UserName=="").ToList();
foreach(UserProfile item in selecteditem)
{
item.UserName = "NA";
}
我之前提到过应该可以帮助你显着改进这些代码。 请记住,关于如何让IEnumerable项目遍历集合,而不重复它呢? 想想如果你这样写代码会发生什么,取而代之的是:
List<UserProfile> users = new List<UserProfile>();
// ..load users with list of users
var selecteditem = users.Where(i => i.UserName=="");
foreach(UserProfile item in selecteditem)
{
item.UserName = "NA";
}
我所做的只是删除对.ToList()
的调用,但一切仍将工作。 唯一改变的是我们避免需要复制整个列表。 这应该使这个代码更快。 在某些情况下,它可以使代码快了很多 。 需要记住的一点是:在使用linq运算符方法进行工作时,通常尽可能避免调用.ToArray()
或.ToList()
,这可能比您想象的要多得多。
至于foreach() {...}
vs .Foreach( ... )
:前者依然是完全合适的风格。
当然,这很简单。 List
有一个ForEach方法。 IEnumerable
没有这样的方法或扩展方法。
至于为什么有一种方法,而另一种则没有,那是一种意见。 如果你对他的感兴趣,Eric Lippert就此话题发表了博文。
链接地址: http://www.djcxy.com/p/52999.html