Revils
Revils

Reputation: 1508

Use a generic method with a list of different type/class

I am trying to build a search function for a List. This is quite simple, however I am trying to have a method, which can take Lists of different types. Take the following example to clearify the question:

The methods SearchGridViewCategorie and SearchGridViewMedewerker both are methods to search the List if it contains the search term.

public static void SearchGridViewMedewerker(ref List<Medewerker> medewerkers, String term) {
    medewerkers = medewerkers.Where(m => m.gebruikersnaam.ToLower().Contains(term.ToLower()) ||
                    m.naam.ToLower().Contains(term.ToLower()) ||
                    m.email.ToLower().Contains(term.ToLower()) ||
                    m.rol.ToLower().Contains(term.ToLower())).ToList();
}

public static void SearchGridViewCategorie(ref List<Categorie> categorieen, String term) {
    categorieen = categorieen.Where(c => c.omschrijving.ToLower().Contains(term.ToLower())).ToList();
}

I am trying to make this search method generic, so that I can pass Lists of different types to the same method. I have tried the following:

public static List<object> SearchGridView(List<object> list, String term) {
    IList<PropertyInfo> properties = list.GetType().GetProperties().ToList();
    List<object> tempList = new List<object>();

        foreach(object o in list){
            foreach (var property in properties) {
                if (property.ToString().Contains(term.ToLower())) {
                    tempList.Add(o);
                }
            }
        }
    return tempList;
}

However with this solution I have to convert the List of Type T to a List of objects prior to passing the List in the method.

That is not what I want. I want to pass a List of any type, process it and return a List of the type that has been given as a parameter. Is this possible?

Upvotes: 1

Views: 2456

Answers (2)

Steven Rands
Steven Rands

Reputation: 5421

It looks like you are trying to simplify code of this nature:

x => x.property.ToLower().Contains(term.ToLower())

where property is a string property and term is the text you want to search for. If so, you could use a LINQ extension method to do this:

public static class Extensions
{
    public static IEnumerable<T> WhereTextInProperties<T>(this IEnumerable<T> source,
        string searchText, params Func<T, string>[] getPropertyValues)
    {
        searchText = searchText.ToLowerInvariant();

        return from element in source
               from getPropertyValue in getPropertyValues
               let propertyValue = getPropertyValue(element)
               where propertyValue.ToLowerInvariant().Contains(searchText)
               select element;
    }
}

Then you would use it like this:

return medewerkers.WhereTextInProperties(term,
    m => m.gebruikersnaam, m => m.naam,
    m => m.email, m => m.rol
    );

You could probably improve this in various different ways (Regex, list of expressions instead of function delegates, etc) but it might work as a starting point.

Upvotes: 1

spender
spender

Reputation: 120518

I think that this is what you mean:

public static IList<T> SearchGridView<T>(IList<T> list, String term) 
{
    IList<PropertyInfo> properties = typeof(T).GetProperties();
    var t = term.ToLower();
    return list
        .Where(item =>
            properties
                .Select(p => p.GetValue(item).ToString())
                .Any(v => v.Contains(t)))
        .ToList();
}

Upvotes: 3

Related Questions