Reflection to Filter List<T>

3.6k views Asked by At

I am new to Reflection so please excuse my noob question. How can I create a Method that takes two Parameters, a Generic List and a String and then finds all items in that List where any property value matches the string.

So for example we have an object with 3 properties, I pass a list of this object to the method and a search string and it returns back a list of objects where any of the properties may contain the search string.

I can do like this :

var temp = list.AsQueryable().Where("SomeField == 1").Select("it");

But how can I make this method Generic so I can pass any List of Objects to it ?

Thanks in advance...

5

There are 5 answers

2
pil0t On BEST ANSWER

If you are using Dynamic Linq, try this

public static IEnumerable<T> Filter<T>(IEnumerable<T> source, string searchStr)
{
    var propsToCheck = typeof (T).GetProperties().Where(a => a.PropertyType == typeof(string));

    var filter = propsToCheck.Aggregate(string.Empty, (s, p) => (s == string.Empty ? string.Empty : string.Format("{0} OR ", s)) + string.Format("{0} == @0", p.Name));

    var filtered = source.AsQueryable().Where(filter, searchStr);
    return filtered;
}
5
fejesjoco On

Use Type.GetProperties() to get all the properties of an object. Use PropertyInfo.GetValue() to get the value of a given property in a given object. You need to figure out how you want a match your string to a DateTime, to numbers, or to other complex objects. Put it all into a function like bool IsMatch(this object obj, string val). Then you can filter your list like list.Where(x => x.IsMatch("something")).

3
Stefan Z Camilleri On

Here you go mate:

    private static void Main(string[] args)
    {
        var list = new List<object> {new {prop1 = "A", prop2 = "B"},new {prop3 = "B", prop4 = "C"}};
        var subList = SearchForStringInProperties(list, "C");
    }

    private static IEnumerable<object> SearchForStringInProperties(IEnumerable<object> list, string searchString)
    {
        return from obj in list where FindStringInObjProperties(obj, searchString) select obj;
    }

    private static bool FindStringInObjProperties(object obj, string searchString)
    {
        return obj.GetType().GetProperties().Any(property => obj.GetType().GetProperty(property.Name).GetValue(obj).ToString().Equals(searchString));
    }
1
Mat J On

If you just want to match the properties with same type as your argument, this extension method can help,

 public static class ListExtensions
{
    public static IEnumerable<T> MatchWithAnyProperty<T, TK>(this IEnumerable<T> list, TK value)
    {
        var argType = typeof (TK);
        var properties = typeof(T).GetProperties().Where(x => x.PropertyType.IsAssignableFrom(argType));

      return  list.Where(item => properties.Any(prop =>
            {
                var propertyValue = prop.GetValue(item, null);
                if (value == null)
                    return propertyValue == null;
                return propertyValue.Equals(value);
            }));
    }
}

This can be used like,

var items = new[]
            {
                new
                    {
                        Name = "Test",
                        Age = 20,
                        Test=25
                    },
                new
                    {
                        Name = "Hello",
                        Age = 10,
                        Test=15
                    },
                new
                    {
                        Name = "T2gdhest",
                        Age = 14,
                        Test=20
                    },
                new
                    {
                        Name = "hai",
                        Age = 33,
                        Test=10
                    },
                new
                    {
                        Name = "why not",
                        Age = 10,
                        Test=33
                    },
            };

       var match= items.MatchWithAnyProperty(10);

        foreach (var item in match)
        {
            Console.WriteLine(item.Name);
        }
        Console.ReadKey();
0
user3041160 On

And there is the old way ...

    public static IList<T> MyMethod<T>(IList<T> myList, string filter)
    {
        if (myList == null) return null;
        if (filter == null) return myList;

        var tfilter = filter.GetType();
        var properties = typeof(T).GetProperties().Where(x => x.PropertyType.FullName == typeof(string).FullName);
        if (!properties.Any()) return null;


        var res = new List<T>();

        foreach(var el in myList)
        {
            foreach(var p in properties)
            {
                if ((string)p.GetValue(el) == filter)
                {
                    res.Add(el);
                    break;
                }
            }
        }
        return res;
    }