C# IEnumerable.contains在集合中找不到匹配项,该集合确实存在

C# IEnumerable.contains在集合中找不到匹配项,该集合确实存在,c#,unit-testing,C#,Unit Testing,我有一个从foo方法返回的IEnumerableMyClass包含一个嵌套类,通常如下所示。问题是断言总是返回false MyClass { SomeNestedClass { public decimal decimalField1; public int intField2; } } 我正在编写一个单元测试来测试Foo方法 // Arrange var expectedItem = new MyClass { n

我有一个从foo方法返回的
IEnumerable
MyClass
包含一个嵌套类,通常如下所示。问题是断言总是返回false

MyClass
{
    SomeNestedClass
    {
        public decimal  decimalField1;
        public int      intField2;
    }
}
我正在编写一个单元测试来测试
Foo
方法

// Arrange
var expectedItem = new MyClass 
{
    new SomeNestedClass
    {
        decimalField1 = 10M,
        intField2 = 20
    }
}

// Act
var results = sut.Foo();

// Assert
Assert.IsTrue(results.Contains(expectedItem));

问题是Assert总是false。

我们没有足够的信息(sut.Foo();)的实现),但我怀疑您必须重写MyClass类型中的Object.Equals()方法。
如果没有该选项,Contains()函数将仅检查引用的相等性。

Contains
将在尝试查找匹配项时使用类型的默认相等性比较器,这是类等引用类型的引用比较。因为我们知道列表中没有对您刚刚创建的对象的引用,所以这将不起作用

解决此问题的一个简单方法是使用
System.Linq
方法
Any()
,如果
IEnumerable
中的任何项满足指定条件,该方法将返回true

例如:

Assert.IsTrue(results.Any(result => 
    result.decimalField1 == expectedItem.decimalField1 &&
    result.intField2 == expectedItem.intField2));

一种稍微费力但可重复使用的方法是编写一个
SomeNestedClass
比较器,它可以传递给
Contains
方法(我正在使用
SomeNestedClass
,尽管在示例中
result
被声明为
MyClass
,因为这是唯一一个具有可用于比较的字段的类):


可能不会比较同一个对象。可以使用FirstOrDefault(x=>x.decimalField==expectemItem.decimalField&&x.intField2==expectedItem.inteField2)引用相等是默认值。仅仅因为两个对象看起来相同,并不意味着.NET认为它们相等。
public class SomeNestedClassComparer : IEqualityComparer<MyClass.SomeNestedClass>
{
    public bool Equals(MyClass.SomeNestedClass x, MyClass.SomeNestedClass y)
    {
        if (x == null || y == null) return ReferenceEquals(x, y);
        return x.decimalField1 == y.decimalField1 && x.intField2 == y.intField2;
    }

    public int GetHashCode(MyClass.SomeNestedClass obj)
    {
        return obj.decimalField1.GetHashCode() * 17 + 
               obj.intField2.GetHashCode();
    }
}
Assert.IsTrue(results.Contains(expectedItem, new SomeNestedClassComparer()));