比较 2 个忽略顺序的对象列表

Comparing 2 lists of objects ignoring order

即使两个列表包含相同的对象,使用 MSTest V2 和 CollectionAssert.AreEquivalent() 也会失败:

// User-defined object
public class ClientDto
{
    public string FullName { get; set; }

    public decimal RentShare { get; set; }
}


// Test method
var expectedShares = new List<ClientDto>
{
    new ClientDto
    {
        FullName = "Harry Potter",
        RentShare = 500m
    },
    new ClientDto
    {
        FullName = "Ron Weasley",
        RentShare = 300m
    },
};
var actualShares = new List<ClientDto>
{
    new ClientDto
    {
        FullName = "Ron Weasley",
        RentShare = 300m
    },
    new ClientDto
    {
        FullName = "Harry Potter",
        RentShare = 500m
    },
};
CollectionAssert.AreEquivalent(expectedShares, actualShares);

ClientDto还有什么需要实现的吗?

因为 class ClientDto 没有实现 IEquatable<ClientDto>IEquatable,所以使用引用相等来比较实例。

因此,列表中的实例将无法比较 - 即使它们包含相同的数据 - 因为它们的引用不同。

要解决此问题,只需实施 IEquatable<ClientDto> 以便 CollectionAssert.AreEquivalent() 可以正确比较对象:

public class ClientDto: IEquatable<ClientDto>
{
    public string FullName { get; set; }

    public decimal RentShare { get; set; }

    public bool Equals(ClientDto? other)
    {
        if (ReferenceEquals(null, other))
            return false;
        if (ReferenceEquals(this, other))
            return true;

        return FullName == other.FullName && RentShare == other.RentShare;
    }

    public override bool Equals(object? obj)
    {
        if (ReferenceEquals(null, obj))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        if (obj.GetType() != this.GetType())
            return false;
        return Equals((ClientDto) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (FullName.GetHashCode() * 397) ^ RentShare.GetHashCode();
        }
    }

    public static bool operator ==(ClientDto? left, ClientDto? right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(ClientDto? left, ClientDto? right)
    {
        return !Equals(left, right);
    }
}

(由 Resharper 提供实施。)

请注意,对于最新版本的 .Net Core 和 C#,您可以使用 record 而不是 class,因为 record 为您实现了 IEquatable (以及其他一些东西):

public record ClientDto
{
    public string  FullName  { get; set; }
    public decimal RentShare { get; set; }
}