【问题标题】:Linq query filter with "contains" with list<T> multiple elements带有“包含”列表<T>多个元素的Linq查询过滤器
【发布时间】:2016-10-19 20:06:09
【问题描述】:

我想通过 Linq 查询一个列表,但在我的示例中通过另一个包含两个元素(名称、状态)的列表进行过滤。 这是受到我已经适应我的问题的一个老问题的启发。 LINQ: "contains" and a Lambda query (在这个答案中,它只适用于一个元素,即状态)

我尝试使用“包含”方法,但未能成功过滤我的列表。

我应该得到一个只有两座建筑物(二、五)的结果 有人知道我在哪里停下来吗?

谢谢

块引用

    public class Building
    {
        public enum StatusType
        {
            open,
            closed,
            weird,
        };

        public string Name { get; set; }
        public StatusType Status { get; set; }
    }

    private static readonly List<Building> BuildingList = new List<Building>()
    {
        new Building() {Name = "one", Status = Building.StatusType.open},
        new Building() {Name = "two", Status = Building.StatusType.closed},
        new Building() {Name = "three", Status = Building.StatusType.weird},
        new Building() {Name = "four", Status = Building.StatusType.open},
        new Building() {Name = "five", Status = Building.StatusType.closed},
        new Building() {Name = "six", Status = Building.StatusType.weird},
    };

    private  void GetResult()
    {
        var buildingSelect = new List<Building>
        {
            new Building() {Name = "two", Status = Building.StatusType.closed},
            new Building() {Name = "five", Status = Building.StatusType.closed}
        };

        var q = (from building in BuildingList
            where buildingSelect.Contains(building.Name, building.Status)
            select building).ToList();

        dataGridView1.DataSource = q;
    }

【问题讨论】:

    标签: linq list contains


    【解决方案1】:

    您的 LINQ 的主要问题是您正在尝试比较两个 Buildings 的相等性,LINQ 只能通过它们的引用进行比较,因为 Building 没有实现 IEquatable&lt;Building&gt; 也没有覆盖 object.Equals

    解决此问题的一种方法是根据@Wayne 的回答手动指定要比较哪些属性是否相等。

    另一种方法是,如果Building 实例的值与它们的引用相等,则实现IEquatable&lt;Building&gt; 并覆盖object.Equals

    public class Building : IEquatable<Building>
    {
        public Building(string name, StatusType status)
        {
            Name = name;
            Status = status;
        }
    
        public enum StatusType
        {
            open,
            closed,
            weird,
        };
    
        public string Name { get; }
    
        public StatusType Status { get; }
    
        public static bool operator ==(Building left, Building right)
            => Equals(left, right);
    
        public static bool operator !=(Building left, Building right)
            => !Equals(left, right);
    
        public override bool Equals(object obj) => Equals(obj as Building);
    
        public bool Equals(Building other)
        {
            if (ReferenceEquals(this, other))
            {
                return true;
            }
    
            if (ReferenceEquals(other, null) || GetType() != other.GetType())
            {
                return false;
            }
    
            return Name == other.Name && Status == other.Status;
        }
    
        public override int GetHashCode()
        {
            unchecked
            {
                int hash = 17;
                hash = hash * 23 + Name?.GetHashCode() ?? 0;
                hash = hash * 23 + Status.GetHashCode();
                return hash;
            }
        }
    }
    

    这样,您的原始代码将起作用,因为 List.Contains 现在将使用您的 IEquatable&lt;Building&gt; 实现来检查是否相等。

    【讨论】:

    • 感谢 rexcfnghk,我已经学习并尝试了 IEquatable 实现。包含现在正在我的原始代码中进行一些细微的更新 > 'where buildingSelect.Contains(new Building(building.Name, building.Status))' 。列表中的删除也有效。伟大的。非常感谢。
    • 如果我的回答对您有帮助,请考虑接受它作为回答
    【解决方案2】:

    你的意思是这样的?

        var q = from b in BuildingList
            from bs in buildingSelect
            where b.Name == bs.Name && b.Status == bs.Status
            select b;
    

    或许:

        var q = from b in BuildingList
            join bs in buildingSelect
            on new { b.Name, b.Status } equals new { bs.Name, bs.Status }
            select b;
    

    【讨论】:

    • 我只剩下一个问题,因为我需要通过删除一些这样的行来修改 buildingSelect 列表:'code buildingSelect.Remove(new Building() {Name = "two", Status = Building .StatusType.closed}); '这行不通。任何想法来纠正这个。问候。
    • 查看 rexcfnghk 的回答。如果您的Building 对象没有实现GetHashCodeEqualsList.Remove 将使用引用相等,因此您的new Building 将永远不会存在于buildingSelect 集合中,并且根据定义不能被删除。
    【解决方案3】:

    如果有意义的话,您可以覆盖类本身中的相等性。

    或者直接用Any()进行正常检查,像这样:

        var q = (from building in BuildingList
            where buildingSelect.Any(b => b.Name == building.Name 
                                          && b.Status == building.Status)
            select building).ToList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-30
      相关资源
      最近更新 更多