带“的Linq查询筛选器”;包括「;带列表<;T>;多元
在我的示例中,我希望通过Linq查询列表,但通过包含两个元素(名称、状态)的其他列表进行过滤。 这是一个老问题的启发,我已经适应了我的问题。 (在这个答案中,它只适用于一个元素,即状态) 我尝试使用“contains”方法,但未能成功筛选我的列表 我应该得到一个只有两栋楼(二,五栋)的结果 有人知道我停在哪里了吗 谢谢 大宗报价带“的Linq查询筛选器”;包括「;带列表<;T>;多元,linq,list,contains,Linq,List,Contains,在我的示例中,我希望通过Linq查询列表,但通过包含两个元素(名称、状态)的其他列表进行过滤。 这是一个老问题的启发,我已经适应了我的问题。 (在这个答案中,它只适用于一个元素,即状态) 我尝试使用“contains”方法,但未能成功筛选我的列表 我应该得到一个只有两栋楼(二,五栋)的结果 有人知道我停在哪里了吗 谢谢 大宗报价 公共类建筑 { 公共枚举状态类型 { 打开 关闭 奇怪的 }; 公共字符串名称{get;set;} 公共状态类型状态{get;set;} } 私有静态只读列表Build
公共类建筑
{
公共枚举状态类型
{
打开
关闭
奇怪的
};
公共字符串名称{get;set;}
公共状态类型状态{get;set;}
}
私有静态只读列表BuildingList=新列表()
{
新建建筑(){Name=“one”,Status=Building.StatusType.open},
新建建筑(){Name=“two”,Status=Building.StatusType.closed},
new Building(){Name=“three”,Status=Building.StatusType.wird},
新建建筑(){Name=“four”,Status=Building.StatusType.open},
新建建筑(){Name=“five”,Status=Building.StatusType.closed},
new Building(){Name=“six”,Status=Building.StatusType.wird},
};
私有void GetResult()
{
var buildingSelect=新列表
{
新建建筑(){Name=“two”,Status=Building.StatusType.closed},
新建建筑(){Name=“five”,Status=Building.StatusType.closed}
};
var q=(来自BuildingList中的building)
其中buildingSelect.Contains(building.Name、building.Status)
选择building).ToList();
dataGridView1.DataSource=q;
}
你的意思是这样的
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;
LINQ的主要问题是,您正在尝试比较两个
建筑
的相等性,LINQ只能通过它们的引用进行比较,因为建筑
既不实现IEquatable
也不覆盖对象。相等
解决此问题的一种方法是根据@Wayne的答案手动指定要比较的属性是否相等
另一种方法是,如果构建
实例意味着通过它们的值而不是它们的引用来等同,则实现IEquatable
并重写对象。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;
}
}
}
公共类建筑:IEquatable
{
公共建筑(字符串名称、状态类型状态)
{
名称=名称;
状态=状态;
}
公共枚举状态类型
{
打开
关闭
奇怪的
};
公共字符串名称{get;}
公共状态类型状态{get;}
公共静态布尔运算符==(建筑左侧、建筑右侧)
=>等于(左、右);
公共静态布尔运算符!=(建筑左侧、建筑右侧)
=>!等于(左、右);
公共覆盖布尔等于(对象对象obj)=>Equals(对象obj作为建筑);
公共布尔等于(建筑其他)
{
if(ReferenceEquals(this,other))
{
返回true;
}
if(ReferenceEquals(other,null)| | GetType()!=other.GetType())
{
返回false;
}
返回Name==other.Name&&Status==other.Status;
}
公共覆盖int GetHashCode()
{
未经检查
{
int hash=17;
hash=hash*23+Name?.GetHashCode()??0;
hash=hash*23+Status.GetHashCode();
返回散列;
}
}
}
这样,您的原始代码就可以工作了,因为
List.Contains
现在将使用您的IEquatable
实现来检查相等性。如果有意义,您可以覆盖类本身中的相等性
或者只需使用Any()
进行正常检查,如下所示:
var q = (from building in BuildingList
where buildingSelect.Any(b => b.Name == building.Name
&& b.Status == building.Status)
select building).ToList();
我只剩下一个问题,因为我需要通过删除一些行来修改buildingSelect列表,如下所示:“code buildingSelect.Remove(new Building(){Name=“two”,Status=Building.StatusType.closed};”这不管用。有没有办法纠正这个问题。您好,请参阅rexcfnghk的回答<代码>列表。如果您的
Building
对象未实现GetHashCode
和Equals
,则Remove将使用引用相等,因此您的新建筑将永远不存在于buildingSelect
集合中,并且根据定义无法删除。感谢rexcfnghk,通过这一点,我学习并试验了IEquatable实现。Contains现在正在对我的原始代码>“where buildingSelect.Contains(new Building(Building.Name,Building.Status))”进行一些细微的更新。在列表中删除也可以。伟大的非常感谢。如果我的回答帮助了你,请考虑接受它作为回答。
var q = (from building in BuildingList
where buildingSelect.Any(b => b.Name == building.Name
&& b.Status == building.Status)
select building).ToList();