繁体   English   中英

C#扩展方法

[英]C# 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));
 }

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

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

提前致谢,
桑尼

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

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

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

现在当你说:

source = source.Where(....);

您正在将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));
 }

这就是假设您希望将它完全保持为IEnumerable<T>正如您在问题中所提到的那样。 显然,正如其他示例中所指出的,如果您只关心List<T>则会有一个带烘焙的RemoveAll()方法。

应该通过返回一个新序列来实现这种扩展。 这样您就可以集成到一系列序列操作中:

public static IEnumerable<T> Remove<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Where(t => !predicate(t));
}

var query = mySequence.Select(x => x.Y).Remove(x => x == 2).Select(x => 2*x);

现在这个方法只不过是Where()的包装器,这显然没有用。 你可以考虑摆脱它。

如果你想实际更新底层集合(假设它甚至存在)那么你不能这样做,因为IEnumerable<T>没有提供任何改变其内容的方法。 你必须做类似的事情:

var myNewList = new List<int>(oldList.Remove(x => x == 2));

最后,如果你正在使用List<T>你可以使用RemoveAll()方法来实际从列表中删除项目:

int numberOfItemsRemoved = myList.RemoveAll(x => x == 2);

试试这里有一个有用的List.RemoveAll(谓词匹配)方法,我认为是为此设计的: http//msdn.microsoft.com/en-us/library/wdka673a.aspx

所以只需在你拥有的列表中使用它。

source.RemoveAll(t => !items.Contains(t))

或者你的扩展方法返回所需的可枚举,你可以使用它。

这是因为IEnumerable是不可变的你必须从Remove方法返回另一个序列才能工作:

public static IEnumerable<T> Remove<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
   var items = source.Where(predicate);

   return source.Where(t => !items.Contains(t));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM