.Contains() 在自定义类对象列表中
Posted
技术标签:
【中文标题】.Contains() 在自定义类对象列表中【英文标题】:.Contains() on a list of custom class objects 【发布时间】:2011-02-07 10:02:20 【问题描述】:我正在尝试对自定义对象列表使用 .Contains()
函数
这是列表:
List<CartProduct> CartProducts = new List<CartProduct>();
还有CartProduct
:
public class CartProduct
public Int32 ID;
public String Name;
public Int32 Number;
public Decimal CurrentPrice;
/// <summary>
///
/// </summary>
/// <param name="ID">The ID of the product</param>
/// <param name="Name">The name of the product</param>
/// <param name="Number">The total number of that product</param>
/// <param name="CurrentPrice">The currentprice for the product (1 piece)</param>
public CartProduct(Int32 ID, String Name, Int32 Number, Decimal CurrentPrice)
this.ID = ID;
this.Name = Name;
this.Number = Number;
this.CurrentPrice = CurrentPrice;
public String ToString()
return Name;
所以我尝试在列表中找到类似的购物车产品:
if (CartProducts.Contains(p))
但它忽略了类似的购物车产品,我似乎不知道它检查什么 - ID?还是全部?
提前致谢! :)
【问题讨论】:
【参考方案1】:默认情况下,引用类型具有引用相等性(即两个实例仅在它们是同一个对象时才相等)。
您需要覆盖 Object.Equals
(和 Object.GetHashCode
以匹配)以实现您自己的相等性。 (然后实现一个相等,==
,运算符是一个很好的做法。)
【讨论】:
为什么要重写 Object.Equals,这可能会在代码的其他地方产生影响?对我来说,相应地修改搜索代码而不是正在搜索的对象的底层类更有意义...... 你有没有这方面的一些例子,.Find() 或覆盖 Object.Equals/GetHashCode?span> @Martin IT 如果您想比较两个CartProduct
对象在不同位置的行为不同,那将会非常糟糕。
@Rowland - 但我并不是说他必须改变比较的工作方式。如果他想要一个特定的对象,请使用 Contains()。如果他想要任何符合指定条件的对象,请使用 Find() 和合适的谓词(lamda 表达式)......我实际上是在争辩说你根本不接触比较代码 - 你只需调用正确的方法列出您要完成的任务...
@Martin 看来我将您的评论误解为类似于“覆盖Contains()
”的内容。同意Find()
可以解决这个问题,尽管我建议有一个合适的 equals 方法在其他情况下可能更有用,因为 OP 没有发现同一实体的两个实例的引用是不同的。
【参考方案2】:
如果您想对此进行控制,您需要实现 [IEquatable 接口][1]
[1]:http://This 方法使用默认相等比较器确定相等性,该比较器由对象对 T(列表中值的类型)的 IEquatable.Equals 方法的实现定义。
【讨论】:
【参考方案3】:你需要实现IEquatable
或者覆盖Equals()
和GetHashCode()
例如:
public class CartProduct : IEquatable<CartProduct>
public Int32 ID;
public String Name;
public Int32 Number;
public Decimal CurrentPrice;
public CartProduct(Int32 ID, String Name, Int32 Number, Decimal CurrentPrice)
this.ID = ID;
this.Name = Name;
this.Number = Number;
this.CurrentPrice = CurrentPrice;
public String ToString()
return Name;
public bool Equals( CartProduct other )
// Would still want to check for null etc. first.
return this.ID == other.ID &&
this.Name == other.Name &&
this.Number == other.Number &&
this.CurrentPrice == other.CurrentPrice;
【讨论】:
但是GetHashCode()
在哪里?
你不需要实现GetHashCode()。没有它也可以工作。【参考方案4】:
它检查特定对象是否包含在列表中。
使用列表中的 Find 方法可能会更好。
这是一个例子
List<CartProduct> lst = new List<CartProduct>();
CartProduct objBeer;
objBeer = lst.Find(x => (x.Name == "Beer"));
希望有帮助
您还应该看看 LinQ - 这可能有点矫枉过正,但仍然是一个有用的工具......
【讨论】:
Linq 怎么可能会矫枉过正? @MEL - 为什么要在查询和类型推断中混淆这么简单的事情?尽管如此,对于不熟悉 lamdas 的人来说,它可能更具可读性...... +1 很好的清晰示例,显示了不受其他地方更改影响的选项(即,如果Equals()
方法因任何原因而更改)【参考方案5】:
如果您使用的是 .NET 3.5 或更新版本,您可以使用 LINQ 扩展方法通过 Any
扩展方法实现“包含”检查:
if(CartProducts.Any(prod => prod.ID == p.ID))
这将检查CartProducts
中是否存在具有与p
ID 匹配的ID 的产品。您可以在=>
之后放置任何布尔表达式来执行检查。
这还具有适用于 LINQ-to-SQL 查询以及内存中查询的好处,而 Contains
则不行。
【讨论】:
【参考方案6】:实现override Equals()
和GetHashCode()
public class CartProduct
public Int32 ID;
...
public CartProduct(Int32 ID, ...)
this.ID = ID;
...
public override int GetHashCode()
return ID;
public override bool Equals(Object obj)
if (obj == null || !(obj is CartProduct))
return false;
else
return GetHashCode() == ((CartProduct)obj).GetHashCode();
使用:
if (CartProducts.Contains(p))
【讨论】:
【参考方案7】:您需要从列表中创建一个对象,例如:
List<CartProduct> lst = new List<CartProduct>();
CartProduct obj = lst.Find(x => (x.Name == "product name"));
该对象通过其属性搜索查找值:x.name
然后您可以使用 List 方法,例如 Contains 或 Remove
if (lst.Contains(obj))
lst.Remove(obj);
【讨论】:
以上是关于.Contains() 在自定义类对象列表中的主要内容,如果未能解决你的问题,请参考以下文章
在自定义JsonConverter中反序列化嵌套对象List