C#扩展方法

Son*_*Boy 2 .net c# ienumerable lambda extension-methods

我目前正在尝试编写扩展方法,但它似乎没有按预期运行.在我们深入研究之前,这里是我的代码:

 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));
 }
Run Code Online (Sandbox Code Playgroud)

我希望可以在任何IEnumerable上调用此扩展方法,然后从集合中删除与谓词匹配的所有项.我厌倦了遍历集合来查找匹配的项目,然后一次删除它们,以避免在枚举时改变集合......

无论如何......当我单步执行代码时,一切似乎都有效.在存在该方法之前,source具有正确数量的项目被移除.但是,当我返回到调用代码时,所有项目仍然存在于我的原始IEnumerable对象中.有小费吗?

先谢谢,
桑尼

Jam*_*are 11

不能像你最初编写它那样做,你正在使用引用变量(source)并使它引用一个新实例.这会修改本地引用,source而不是传入的原始参数.

请记住C#中的引用类型,默认参数传递方案是按值传递(其中传递的值是引用).

假设您将变量传递x给此方法,该方法引用原始列表,该列表位于理论位置1000,这意味着源是对位于1000位置的原始列表的新引用.

现在当你说:

source = source.Where(....);
Run Code Online (Sandbox Code Playgroud)

您正在分配source一个新列表(例如在位置2000处),但这只会影响您传入的内容source而不是x您传入的内容.

要将此作为扩展方法修复,您真的想要return新的序列:

 public static IEnumerable<T> Remove<T>(this IEnumerable<T> source, Func<T, bool> predicate)
 {
     if (source == null) throw new ArgumentNullException("source");
     if (predicate == null) throw new ArgumentNullException("predicate");

     // you can also collapse your logic to returning the opposite result of your predicate
     return source.Where(x => !predicate(x));
 }
Run Code Online (Sandbox Code Playgroud)

这就是假设您希望保持完全通用,IEnumerable<T>就像您在问题中所提到的那样.显然在其他例子中也指出,如果你只关心List<T>有一个烘焙RemoveAll()方法.