Brandon
Brandon

Reputation: 23

How to dynamically get a property value in which is in another property with Linq where statement

I have found some direction for this problem but have not found anything which I can apply to this problem.

I want to filter lists of different types by stated properties they hold. I can use linq to dynamically filter a List by Test.id but I cant manage to filter a List through MyClass.Name

I have these classes.

public class Test
{
    public int Id { get; set; }
    public MyClass myclass { get; set; }
}

public class MyClass
{
    public string Name { get; set; }
}

This is what I'm trying to do.

static void Main(string[] args)
{             
    var source = new List<Test> {
        new Test { Id = 1,myclass = new MyClass() { Name = "bob" } },
        new Test { Id = 2,myclass= new MyClass() { Name = "joe" } } };

    var x = myFilter(source,"Name", "bob");
    Console.WriteLine(x.Count());
}

public static IEnumerable<T> myFilter<T>(List<T> source, string propertyName, string searchString)
{
// get the myclass property then the stated property(Name) value within it
    searchString = searchString.ToLower();
    return source.Where(s => (s.GetType().GetProperty("myclass")
                                .GetType().GetProperty(propertyName)
                                .GetValue(s.GetType().GetProperty("myclass"),null).ToString() ?? " ")
                                .ToLower().Contains(searchString));
}

The count return 0 when I am expecting 1. for Test.MyClass.Name = "bob" Is there a solution for this or is there a better way to do it besides reflection?

Thanks

Upvotes: 2

Views: 733

Answers (2)

Stefan William-Worrall
Stefan William-Worrall

Reputation: 713

You should be able to use the following:

var count = source.Count(test => 
                             string.Compare(test.myClass.Name, "Bob", 
                                        StringComparison.CurrentCultureIgnoreCase) == 0);

This will compare the string value of the Name Property and only count where the name is equal to "bob" and it will ignore the case.

If you want to return the Test object instead then you can use the following

var results = source.Where(test => 
                             string.Compare(test.myClass.Name, "Bob", 
                                        StringComparison.CurrentCultureIgnoreCase) == 0);  

Upvotes: 0

Nico
Nico

Reputation: 3542

you need to use the PropertyType of the returned myclass property:

public static IEnumerable<T> myFilter<T>(List<T> source, string propertyName, string searchString)
{
    // get the myclass property then the stated property(Name) value within it
    searchString = searchString.ToLower();
    return source.Where(s => (s.GetType().GetProperty("myclass")
                                .PropertyType.GetProperty(propertyName)
                                .GetValue(s.GetType().GetProperty("myclass").GetValue(s)).ToString() ?? " ")
                                .ToLower().Contains(searchString));
}

Upvotes: 1

Related Questions