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