【问题标题】:How to filter List<object> using Linq/Lambda如何使用 Linq/Lambda 过滤 List<object>
【发布时间】:2016-09-05 20:35:58
【问题描述】:

这是我的场景

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"});

你如何过滤List&lt;object&gt; 这样它返回一个名为“Jakob”的用户列表?

obj.Where(t =&gt; t.name == "Jakob") 不起作用

【问题讨论】:

  • 你最好初始化一个数组,这样它就会采用像var stuff = new [] {new {id=1, name = "Jakob"},....};这样的匿名类型,这样当你做Where时,lambda会知道类型,你可以访问属性.要么从object切换到dynamic

标签: c# linq list object filter


【解决方案1】:

最好的选择是声明一个代表用户的类。

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

然后创建User 对象列表并查询此列表。

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");

否则,您必须依赖 Tengiz 建议的解决方案。

【讨论】:

    【解决方案2】:

    如果您将对象转换为动态对象,它应该可以工作:

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

    编辑

    为了完整起见,我应该提几点:

    • 动态类型的使用归结为在其上使用反射的对象,所以如果使用这种方法,最终你不会得到比反射更好的东西。
    • 完全使用动态涉及将必要的程序集(也称为 DLR)加载到 CLR 中,如果您根本不使用动态,则不会加载。换句话说,这是一种开销。

    所以,请自行决定使用。

    【讨论】:

    • 喜欢你的想法,但它抛出“'object'不包含'name'的定义”
    • 但它对我有用......你确定你提供了你所拥有的确切代码吗?我刚刚在 VS 2013 中尝试过,效果很好。
    • 我试过 "obj.Where(t => ((string)((dynamic)t).name).Contains("Jakob")"
    • 你的表情中噪音太大。如果您想使用 Contains 方法,只需执行此操作: obj.Where(t => ((dynamic)t).name.Contains("Jakob"));这将起作用,因为动态的属性也是动态的。顺便说一句,我也试过这个并且工作正常。如果它对您不起作用,则应该是您未在此处发布的其他内容。
    • 对不起,我无论如何都无法让它工作,我不想在这个线程中浪费你的才能,因为我打算在代码的一个较少使用的区域使用这个线程的答案,但是谢谢为了您的时间和教育同胞:)
    【解决方案3】:

    另一种选择是创建匿名类型数组,然后通过ToListIEnumerable扩展方法将其转换为列表:

    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");
    

    如果您真的不需要列表并且数组也可以 - 只是不要转换为列表。好处是你得到了强类型列表,而不是任意对象的列表。

    【讨论】:

    • 当您可以在创建时初始化集合时,您既不需要new[] 也不需要ToList() 来执行查询,因为objIEnumerable&lt;anonyomusType&gt; 的一个实例。问题是,当您无法在创建时进行初始化时。
    • 作者没有说他不能在创建时初始化。 ToList 适用于作者以后需要添加更多对象的情况。
    【解决方案4】:

    你可以使用反射

        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");
    

    获取元素的类型并找到您要查找的属性。然后获取当前实例的值并将其与您要过滤的值进行比较。

    但另一方面,这种方法的优点是即使 List 包含多个不同匿名类型的项目(如果它们具有不同的属性),只要它们都具有您要过滤的属性。

    编辑

    在 c# 6 中,您可以使用 ? 运算符,这是一种对 null 的内联检查。即,如果GetProperty()因为找不到属性而返回null,则表达式返回null而不执行GetValue()(否则会抛出NullReferenceException

    【讨论】:

    • 感谢您的解决方案对我有用。我想反射是唯一的解决方案。我通常会离开反射,但绝望的时间需要绝望的措施。我太深了,无法使用其他方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 2014-10-16
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    相关资源
    最近更新 更多