[英]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.