何时应该使用IEqualityComparer?C#

4

我有一个自定义对象列表,想要删除其中的重复记录。我看到很多在线文章都指向了IEqualityComparer(我以前从未使用过它)。

问题是,何时应该使用它?我可以在一行代码中通过LINQ实现相同的结果。

例如:

public static void Main(string[] args)
{
    Product[] products =
    {
        new Product {Name = "apple", Code = 9},
        new Product {Name = "orange", Code = 4},
        new Product {Name = "apple", Code = 9},
        new Product {Name = "lemon", Code = 12}
    };

    // Using Custom comparer
    var usingCustomComparer = products.Distinct(new ProductComparer()).ToList();

    // Using LINQ
    var usinLinq = products.GroupBy(x => x.Name).Select(y => y.First()).ToList();
}

public class Product
{
    public string Name { get; set; }
    public int Code { get; set; }
}

// Custom comparer for the Product class
private class ProductComparer : IEqualityComparer<Product>
{
    public bool Equals(Product x, Product y)
    {
        if (ReferenceEquals(x, y)) return true;

        if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;

        return x.Code == y.Code && x.Name == y.Name;
    }

    public int GetHashCode(Product product)
    {
        var hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();

        var hashProductCode = product.Code.GetHashCode();

        return hashProductName ^ hashProductCode;
    }
}

两者的结果:

{Name = "apple", Code = 9},
{Name = "orange", Code = 4},
{Name = "lemon", Code = 12}

2
你能保证每次使用Linq语句时都以相同的方式编写吗?或者如果你需要更改比较器的排序方式,那么你必须全部更改吗?假设你在500个地方进行了比较,其中一些在第三方代码中,现在你面临维护噩梦。 - Ron Beyer
如果需要默认比较器,则接口是一个好主意。如果没有默认比较器或其他预先编写的比较器可用,则LINQ很好。请注意,接口比LINQ旧一点。它是在.NET 2.0(2006年1月)中引入的。LINQ仅在3.5(2007年11月)中添加。因此,如果您有需要比较器的预编写代码,则可以假定它将寻找已实现IEqualityComparer。如果存在,则字典添加或任何集合上的查找可能使用IEqualityComparer。 - Christopher
3个回答

2

什么时候应该使用它?

一些可能的情况:

  • 当你对“相等性”的定义比仅比较一个属性更复杂时
  • 当你想预先定义“相等性”以在许多查询中使用时
  • 当你想在 Linq 之外定义“相等性”,例如将类作为哈希表的键时
  • 当你想微调相等性定义而不重复代码时(即打开/关闭大小写敏感性)

感谢您的详细解释。 - GThree

1

假设您想比较对象时忽略大小写,使得 "Apple" 和 "apple" 被视为相同的对象。那么您的 ProductComparer 可以如下所示:

class ProductComparer : IEqualityComparer<Product>
{
    public bool Equals(Product x, Product y)
    {
        if (ReferenceEquals(x, y)) return true;

        if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;

        return x.Code == y.Code && (x.Name.Equals(y.Name, StringComparison.InvariantCultureIgnoreCase));
    }

    public int GetHashCode(Product product)
    {
        var hashProductName = product.Name == null ? 0 : product.Name.ToLower().GetHashCode();

        var hashProductCode = product.Code.GetHashCode();

        return hashProductName ^ hashProductCode;
    }
}

它将产生与 Linq 不同的结果。


有意义。谢谢。 - GThree
这仍然会得到相同的答案,因为您没有修复HashCode部分吗? - Kid

0

大多数情况下,比较可以使用一些 Linq 实现。如果只是一次性的,那么选择可能只取决于个人喜好。

如果比较逻辑被频繁地重用,创建一个 IEqualityComparer 是一个标准且广为接受的方式,用于比较两个对象。您可以在 Linq 方法、集合等中重复使用实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接