C# Select 和 ForEach on List<>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17733466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Select and ForEach on List<>
提问by ammu
I am quite new to C# and was trying to use lambda expressions.
我对 C# 很陌生,并试图使用 lambda 表达式。
I am having a list of object. I would like to select item from the list and perform foreach operation on the selected items. I know i could do it without using lambda expression but wanted to if this was possible using lambda expression.
我有一个对象列表。我想从列表中选择项目并对所选项目执行 foreach 操作。我知道我可以在不使用 lambda 表达式的情况下做到这一点,但想使用 lambda 表达式是否可行。
So i was trying to achieve a similar result
所以我试图达到类似的结果
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";
}
it was possible to do
有可能做
users.Where(i => i.UserName=="").ToList().ForEach(i=>i.UserName="NA");
but not something like this
但不是这样的
users.select(i => i.UserName=="").ForEach(i=>i.UserName="NA");
Can someone explain this behaviour..
有人可以解释这种行为..
采纳答案by Joel Coehoorn
Let's start here:
让我们从这里开始:
I am having a list of object.
我有一个对象列表。
It's important to understand that, while accurate, that statement leaves a c# programmer wanting more. What kind of object? In the .Net world, it pays to always keep in mind what specific type of object you are working with. In this case, that type is UserProfile
. This may seem like a side issue, but it will become more relevant to the specific question very quickly. What you want to say instead is this:
重要的是要理解,虽然准确,但该声明让 ac# 程序员想要更多。什么样的对象?在 .Net 世界中,始终牢记您正在使用的特定类型的对象是值得的。在这种情况下,该类型是UserProfile
。这似乎是一个附带问题,但它很快就会与特定问题变得更加相关。你想说的是:
I have a list of UserProfile objects.
我有一个 UserProfile 对象列表。
Now let's look at your two expressions:
现在让我们看看你的两个表达式:
users.Where(i => i.UserName=="").ToList().ForEach(i=>i.UserName="NA");
users.Where(i => i.UserName=="").ToList().ForEach(i=>i.UserName="NA");
and
和
users.Where(i => i.UserName=="").ForEach(i=>i.UserName="NA");
users.Where(i => i.UserName=="").ForEach(i=>i.UserName="NA");
The difference (aside from that only the first compiles or works) is that you need to call .ToList()
to convert the results of Where()
function to a List type. Now we begin to see whyit is that you want to always think in terms of types when working with .Net code, because it should now occur to you to wonder, "What type am I working with, then?" I'm glad you asked.
不同之处(除了只有第一个编译或工作)是您需要调用.ToList()
将Where()
函数的结果转换为 List 类型。现在我们开始明白为什么在使用 .Net 代码时你总是想从类型的角度来思考,因为你现在应该想知道,“那么我在使用什么类型?” 我很高兴你问。
The .Where()
function results in an IEnumerable<T>
type, which is actually not a full type all by itself. It's an interfacethat describes certain things a type that implements it's contract will be able to do. The IEnumerable interface can be confusing at first, but the important thing to remember is that it defines something that you can use with a foreach
loop. That is it's sole purpose. Anything in .Net that you can use with a foreach loop: arrays, lists, collections — they pretty much all implement the IEnumerable interface. There are other things you can loop over, as well. Strings, for example. Many methods you have today that require a List or Array as an argument can be made more powerful and flexible simply by changing that argument type to IEnumerable.
该.Where()
函数产生一个IEnumerable<T>
类型,它本身实际上并不是一个完整的类型。它是一个接口,它描述了实现它的契约的类型将能够做的某些事情。IEnumerable 接口一开始可能会令人困惑,但要记住的重要一点是它定义了一些可以与foreach
循环一起使用的东西。这是它的唯一目的。.Net 中可以与 foreach 循环一起使用的任何东西:数组、列表、集合——它们几乎都实现了 IEnumerable 接口。您还可以循环其他内容。以字符串为例。您现在拥有的许多需要 List 或 Array 作为参数的方法可以通过将该参数类型更改为 IEnumerable 来变得更加强大和灵活。
.Net also makes it easy to create state machine-based iterators that will work with this interface. This is especially useful for creating objects that don't themselves hold any items, but do know how to loop over items in a different collection in a specific way. For example, I might loop over just items 3 through 12 in an array of size 20. Or might loop over the items in alphabetical order. The important thing here is that I can do this without needing to copy or duplicate the originals. This makes it very efficient in terms of memory, and it's structure in such a way that you can easily compose different iterators together to get very powerful results.
.Net 还可以轻松创建与此接口一起使用的基于状态机的迭代器。这对于创建本身不包含任何项目但知道如何以特定方式循环不同集合中的项目的对象特别有用。例如,我可能只遍历大小为 20 的数组中的第 3 到 12 项。或者可能按字母顺序遍历这些项。这里重要的是,我可以在不需要复制或复制原件的情况下做到这一点。这使得它在内存方面非常有效,并且它的结构使您可以轻松地将不同的迭代器组合在一起以获得非常强大的结果。
The IEnumerable<T>
type is especially important, because it is one of two types (the other being IQueryable) that form the core of the linq system. Most of the .Where()
, .Select()
, .Any()
etc linq operators you can use are defined as extensionsto IEnumerable.
的IEnumerable<T>
类型是特别重要的,因为它是两种类型的(另一个是IQueryable的),其形成所述LINQ系统的核心中的一个。在大多数情况下.Where()
,.Select()
,.Any()
等LINQ运营商可以使用被定义为扩展到IEnumerable的。
But now we come to an exception: ForEach()
. This method is notpart of IEnumerable. It is defined directly as part of the List<T>
type. So, we see again that it's important to understand what type you are working with at all times, including the results of each of the different expressions that make up a complete statement.
但是现在我们遇到了一个例外:ForEach()
. 此方法不是IEnumerable 的一部分。它被直接定义为List<T>
类型的一部分。因此,我们再次看到,始终了解您正在使用的类型很重要,包括构成完整语句的每个不同表达式的结果。
It's also instructional to go into whythis particular method is not part of IEnumerable directly. I believe the answer lies in the fact that the linq system takes a lot of inspiration from a the Functional Programming world. In functional programming, you want to have operations (functions) that do exactly one thing, with no side effects. Ideally, these functions will not alterthe original data, but rather they will return new data. The ForEach()
method is implicitly all about creating bad side effects that alter data. It's just bad functional style. Additionally, ForEach() breaks method chaining, in that it doesn't return a new IEnumerable.
解释为什么这个特定方法不是 IEnumerable 直接的一部分也是有指导意义的。我相信答案在于 linq 系统从函数式编程世界中汲取了很多灵感。在函数式编程中,您希望操作(函数)只做一件事,没有副作用。理想情况下,这些函数不会改变原始数据,而是会返回新数据。该ForEach()
方法隐含地都是关于创建改变数据的不良副作用。这只是糟糕的功能风格。此外,ForEach() 会中断方法链,因为它不会返回新的 IEnumerable。
There is one more lesson to learn here. Let's take a look at your original snippet:
这里还有一课要学习。让我们来看看您的原始代码段:
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";
}
I mentioned something earlier that should help you significantly improve this code. Remember that bit about how you can have IEnumerable items that loop over a collection, without duplicating it? Think about what happens if you wrote that code this way, instead:
我之前提到了一些应该可以帮助您显着改进此代码的内容。还记得关于如何让 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";
}
All I did was remove the call to .ToList()
, but everything will still work. The only thing that changed is we avoided needing to copy the entire list. That should make this code faster. In some circumstances, it can make the code a lotfaster. Something to keep in mind: when working the with the linq operator methods, it's generally good to avoid calling .ToArray()
or .ToList()
whenever possible, and it's possible a lot more than you might think.
我所做的只是删除对 的调用.ToList()
,但一切仍然有效。唯一改变的是我们避免了需要复制整个列表。这应该使这段代码更快。在某些情况下,它可以使代码中的许多更快。需要记住的一点:在使用 linq 操作符方法时,避免调用.ToArray()
或.ToList()
尽可能避免调用通常是好的,而且它的可能性比您想象的要多得多。
As for the foreach() {...}
vs .Foreach( ... )
: the former is still perfectly appropriate style.
至于foreach() {...}
vs .Foreach( ... )
:前者仍然是非常合适的风格。
回答by Servy
Sure, it's quite simple. List
has a ForEachmethod. There is no such method, or extension method, for IEnumerable
.
当然,这很简单。 List
有一个ForEach方法。没有这样的方法或扩展方法IEnumerable
。
As to why one has a method and another doesn't, that's an opinion. Eric Lippert blogged on the topicif you're interested in his.
至于为什么一个人有方法而另一个人没有,那是一种意见。如果您对Eric Lippert感兴趣,他会在博客上讨论这个话题。