开发者

C# Extension Methods

开发者 https://www.devze.com 2023-03-29 16:29 出处:网络
I\'m currently trying to write an extension method, but it doesn\'t seem to be operating as intended.Before we delve too much deeper, here\'s the code I have:

I'm currently trying to write an extension method, but it doesn't seem to be operating as intended. Before we delve too much deeper, here's the code I have:

 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));
 }

The desire is t开发者_开发问答hat I can call this extension method on any IEnumerable and all items matching the predicate are then removed from the collection. I'm tired of iterating through collections to find the items that match and then removing them one at a time to avoid altering the collection while enumerating through it...

Anyway... When I step through the code, everything seems to work. Before existing the method, the source has the correct number of items removed. However, when I return to the calling code all of the items still exist in my original IEnumerable object. Any tips?

Thanks in advance,

Sonny


Can't do that the way you have originally written it, you are taking a reference variable (source) and making it refer to a new instance. This modifies the local reference source and not the original argument passed in.

Keep in mind for reference types in C#, the default parameter passing scheme is pass by value (where the value being passed is a reference).

Let's say you pass in a variable x to this method, which refers to the original list and that list lives at theoretical location 1000, this means that source is a new reference to the original list living at location 1000.

Now when you say:

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

You are assigning source to a new list (say at location 2000), but that only affects what source points to and not the x you passed in.

To fix this as an extension method, you would really want to return the new sequence instead:

 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));
 }

This is all assuming you want to keep it totally generic to IEnumerable<T> as you asked in your question. Obviously as also pointed out in other examples if you only care about List<T> there is a baked-in RemoveAll() method.


This kind of extension should be implemented by returning a new sequence. That way you can integrate into a chain of sequence operations:

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);

Now the method is nothing but a wrapper around Where(), which obviously isn't helpful. You might consider getting rid of it.

If you want to actually update the underlying collection (assuming that even exists) then you can't do it this way, since IEnumerable<T> doesn't provide any way to alter its contents. You would have to do something like:

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

Finally, if you are working with List<T>, you can use the RemoveAll() method to actually remove items from the list:

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


try this there's a useful List.RemoveAll(Predicate match) method which I think is designed for this: http://msdn.microsoft.com/en-us/library/wdka673a.aspx

so just use this on the list which you have.

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

or your extension method returns you the required enumerable and you can use that.


This is because IEnumerable is immutable You have to return another sequence from your Remove method for this to work:

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));
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号