C# 扩展方法
我目前正在尝试编写一个扩展方法,但它似乎没有按预期运行。在我们深入研究之前,先看一下我的代码: 我的
public static void Remove<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
var items = source.Where(predicate);
source = source.Where(t => !items.Contains(t));
}
愿望是我可以在任何 IEnumerable 上调用此扩展方法,然后从集合中删除与谓词匹配的所有项目。我厌倦了迭代集合以查找匹配的项目,然后一次删除一个项目以避免在枚举集合时更改集合...
无论如何...当我单步执行代码时,一切似乎都有效。在存在该方法之前,源
已删除正确数量的项目。但是,当我返回调用代码时,所有项目仍然存在于我的原始 IEnumerable 对象中。有什么建议吗?
预先感谢,
桑尼
I'm currently trying to write an extension method, but it doesn't seem to be operating as intended. Before we delve too much deeper, here's the code I have:
public static void Remove<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
var items = source.Where(predicate);
source = source.Where(t => !items.Contains(t));
}
The desire is that I can call this extension method on any IEnumerable and all items matching the predicate are then removed from the collection. I'm tired of iterating through collections to find the items that match and then removing them one at a time to avoid altering the collection while enumerating through it...
Anyway... When I step through the code, everything seems to work. Before existing the method, the source
has the correct number of items removed. However, when I return to the calling code all of the items still exist in my original IEnumerable object. Any tips?
Thanks in advance,
Sonny
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
无法按照您最初编写的方式执行此操作,您将获取一个引用变量(
source
)并使其引用一个新实例。这会修改本地引用source
,而不是传入的原始参数。请记住,对于 C# 中的引用类型,默认参数传递方案是按值传递(其中传递的值是引用)。
假设您向此方法传递一个变量
x
,该变量引用原始列表,并且该列表位于理论位置 1000,这意味着 source 是对位于位置 1000 的原始列表的新引用 现在,当您说:
您正在将
source
分配给一个新列表(例如位置 2000),但这只会影响source
指向的内容,而不影响x
你通过了要将其作为扩展方法修复,您确实需要
返回
新序列:这一切都假设您希望使其完全通用于
IEnumerable
正如您在问题中所问的那样。显然,正如其他示例中所指出的,如果您只关心List
,则有一个内置的RemoveAll()
方法。Can't do that the way you have originally written it, you are taking a reference variable (
source
) and making it refer to a new instance. This modifies the local referencesource
and not the original argument passed in.Keep in mind for reference types in C#, the default parameter passing scheme is pass by value (where the value being passed is a reference).
Let's say you pass in a variable
x
to this method, which refers to the original list and that list lives at theoretical location 1000, this means that source is a new reference to the original list living at location 1000.Now when you say:
You are assigning
source
to a new list (say at location 2000), but that only affects whatsource
points to and not thex
you passed in.To fix this as an extension method, you would really want to
return
the new sequence instead:This is all assuming you want to keep it totally generic to
IEnumerable<T>
as you asked in your question. Obviously as also pointed out in other examples if you only care aboutList<T>
there is a baked-inRemoveAll()
method.这种扩展应该通过返回一个新序列来实现。这样您就可以集成到一系列序列操作中:
现在该方法只不过是
Where()
的包装器,这显然没有帮助。您可能会考虑摆脱它。如果您想实际更新底层集合(假设甚至存在),那么您不能这样做,因为
IEnumerable
不提供任何更改其内容的方法。您必须执行以下操作:最后,如果您正在使用
List
,则可以使用RemoveAll()
方法来实际上从列表中删除项目:This kind of extension should be implemented by returning a new sequence. That way you can integrate into a chain of sequence operations:
Now the method is nothing but a wrapper around
Where()
, which obviously isn't helpful. You might consider getting rid of it.If you want to actually update the underlying collection (assuming that even exists) then you can't do it this way, since
IEnumerable<T>
doesn't provide any way to alter its contents. You would have to do something like:Finally, if you are working with
List<T>
, you can use theRemoveAll()
method to actually remove items from the list:试试这个,有一个有用的 List.RemoveAll(Predicate match) 方法,我认为它是为此设计的: http://msdn.microsoft.com/en-us/library/wdka673a.aspx
所以只需在您拥有的列表上使用它即可。
或者您的扩展方法返回所需的枚举,您可以使用它。
try this there's a useful List.RemoveAll(Predicate match) method which I think is designed for this: http://msdn.microsoft.com/en-us/library/wdka673a.aspx
so just use this on the list which you have.
or your extension method returns you the required enumerable and you can use that.
这是因为 IEnumerable 是不可变的
您必须从 Remove 方法返回另一个序列才能使其工作:
This is because IEnumerable is immutable
You have to return another sequence from your Remove method for this to work: