Recently I was working with a generic list containing my own Favorite class. My Favorite class contains an url and a title:
using System.Collections.Generic; public class Favorites { private List<Favorite> _favoriteList = new List<Favorite>(); }
One of the functions on my list is to remove all Favorites with a specific url. I quickly jumped to the help file and found the RemoveAll() function which takes a Predicate. A predicate is a generic delegate that takes the same type as the List<> and returns true if the parameter matches a statement:
public void DinosaurExample() { List<string> dinosaurs = new List<string>(); dinosaurs.Add("Compsognathus"); dinosaurs.Add("Amargasaurus"); dinosaurs.Add("Oviraptor"); dinosaurs.RemoveAll(EndsWithSaurus)); } private static bool EndsWithSaurus(String s) { if ((s.Length > 5) && (s.Substring(s.Length - 6).ToLower() == "saurus")) { return true; } else { return false; } }
The EndsWithSaurus(String s) is the predicate and the function returns true if the matching string ends with “saurus”, removing “Amargasaurus” from the list.
But hey! What if I don’t have a hard-coded match in my code (I rarely have)? The predicate cannot take any parameters. Also, it’s a Static member, polluting my class.
The solution is to create a “predicate class” that takes the expression to match as a parameter:
internal class FavoriteUrlMatch { private string _url; public FavoriteUrlMatch(string url) { _url = url; } public bool Match(Favorite fav) { return fav.Url == _url; } }
Then I can invoke my FavoriteUrlMatch class from my Favorites class:
public void Delete(string url) { FavoriteUrlMatch match = new FavoriteUrlMatch(url); _favoriteList.RemoveAll(match.Match); }
I am not very proud of this solution, but I cannot find a better one.
First of all, in my view predicates should be concise one-line methods – like your EndsWithSaurus method and should therefore be inline anonymous methods. Calling a internal method in a LINQ method makes the code less readable and can lead to nasty things like placing complex business logic in a LINQ query.
Secondly, I’m not sure why your internal method needs to be static. The method this.EndsWithSaurus is not much different from match.Match in this context.
Last but not least, ain’t the LINQ extension methods great?! :-)
LikeLike
The solution is even simpler than I thought, as LINQ will solve my problem.
The following code will remove all favorites where the property “Url” matches my parameter:
public void Delete(string url)
{
_favoriteList.RemoveAll(x => x.Url == url);
}
LikeLike
Thanks. This is exactly what I was looking for!
LikeLike
Pingback: C# Lists in Lists – Getting all inner values, or the unique inner values | Brian Pedersen's Sitecore and .NET Blog
Pingback: C# List Batch – Braking an IEnumerable into batches with .NET | Brian Pedersen's Sitecore and .NET Blog