简体   繁体   中英

How to filter List<object> using Linq/Lambda

Here is my scenario

List<object> obj = new List<object>();
obj.Add(new {id = 1, name = "Jakob"});
obj.Add(new {id = 2, name = "Sam"});
obj.Add(new {id = 3, name = "Albert"});
obj.Add(new {id = 1, name = "Jakob"});

How do you filter List<object> like these so it returns a List of users with name "Jakob"?

obj.Where(t => t.name == "Jakob") doesn't work

If you convert your object to dynamic, it should work:

obj.Where(t => ((dynamic)t).name == "Jakob")

EDIT :

For completeness, I should mention couple of things:

  • Usage of dynamic type comes down to usage of object with reflection on top of it, so eventually you don't get something better than reflection if you use this approach.
  • Usage of dynamic at all involves loading necessary assemblies (aka DLR) into CLR, which would not load if you don't use dynamic at all. In other words, it's an overhead.

So, use with your own discretion.

The best option you have is to declare a class that represents a user.

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Then create a list of User objects and query this list.

var users = new List<User>
{
    new User { Id = 1,  Name = "Jakob" },
    new User { Id = 2,  Name = "Sam" },
    new User { Id = 3,  Name = "Albert" }
}

var filteredUsers = users.Where(user => user.Name == "Jakob");

Otherwise, you have to rely on the solution that Tengiz suggested.

Yet another alternative is create array of anonymous types and then convert it to list via ToList IEnumerable extension method:

var obj = (new[] {
    new { id = 1, name = "Jakob" },
    new { id = 2, name = "Sam" },
    new { id = 3, name = "Albert" },
    new { id = 1, name = "Jakob" }}).ToList();
obj.Where(c => c.name == "Jakob");

If you don't really need a list and array is fine too - just don't convert to list. Benefit is you got strongly typed list and not list of arbitrary objects.

You could use reflection

    var l = new List<object>();
    l.Add(new {key = "key1", v = "value1"});
    l.Add(new {key = "key2", v = "value2", v2="another value"});
    l.Add(new {key = "key3", v = "value3", v3= 4});
    l.Add(new {key = "key4", v = "value4", v4 = 5.3});

    var r = l.Where(x=> (string)x.GetType().GetProperty("key")?.GetValue(x) == "key1");

Get the type of your elements and find the property you are looking for. Then get the value for the current instance and compare it to the value you want to filter for.

But on the other hand, this approach has the advantage of working even if the List contains items of several different anonymous types (if they have different properties), as long as they all have the property you are filtering for.

EDIT

With c# 6 you can use the ? operator, which is sort of an inline check for null. Ie, if GetProperty() returns null because the property is not found, the expression returns null without executing GetValue() (which would otherwise throw a NullReferenceException )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM