簡體   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