C#:如何在检查相等性时评估一个对象的多个计算机类?

标签 c# .net icomparer

动机

我希望实现 IComparer<>以类似于下面的演示代码的方式。在哪里Foo是我需要比较的对象类型。它没有实现 IComparable ,但我提供了一个 IComparer每个字段的类,以便用户可以选择等同于基于一个字段值的实例。

enum Day {Sat, Sun, Mon, Tue, Wed, Thu, Fri};

class Foo {
    public int Bar;
    public string Name;
    public Day Day;
}

比较类是:

// Compares all fields in Foo
public class FooComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        if (ReferenceEquals(x, y)) return true;
        return x.Bar == y.Bar && x.Name == y.Name && return x.Day == y.Day;
    }

    public int GetHashCode(Foo obj)
    {
        unchecked
        {
            var hashCode = obj.Bar;
            hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
            hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
            return hashCode;
        }
    }
}

// Compares only in Foo.Bar
public class FooBarComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        if (ReferenceEquals(x, y)) return true;
        return x.Bar == y.Bar;
    }

    public int GetHashCode(Foo obj)
    {
        unchecked
        {
            var hashCode = obj.Bar;
            hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
            hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
            return hashCode;
        }
    }
}

// Compares only in Foo.Name
public class FooNameComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        if (ReferenceEquals(x, y)) return true;
        return x.Name == y.Name;
    }

    public int GetHashCode(Foo obj)
    {
        unchecked
        {
            var hashCode = obj.Bar;
            hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
            hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
            return hashCode;
        }
    }
}

// Compares only in Foo.Day
public class FooDayComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        if (ReferenceEquals(x, y)) return true;
        return x.Day == y.Day;
    }

    public int GetHashCode(Foo obj)
    {
        unchecked
        {
            var hashCode = obj.Bar;
            hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
            hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
            return hashCode;
        }
    }
}

问题

我想让用户能够组合多个 Comparer类型来评估类型的两个实例 Foo .我不确定该怎么做。

想法

我想出的是这样的,我 AND列表中所有比较器的比较结果:

bool CompareFoo(Foo a, Foo b, params IComparer[] comparers)
{
    bool isEqual = true;
    // Or the list and return;
    foreach (var comparer in comparers)
    {
        isEqual = isEqual && comparer.Equals(x,y);
    }
    return isEqual;
}

注意事项

  • 我的目标 .NET 版本是 4.5 .
  • 我可能会卡在 C# 5.0 上.
  • 此外,可能会卡在 `MSBuild 12.0
  • 这是我第一次使用 IComparer .

最佳答案

您可以组合多个 IEqualityComparer<Foo>通过定义一个将其他比较器作为构造函数参数的附加比较器来对象:

public class CompositeFooComparer : IEqualityComparer<Foo>
{
    private IEqualityComparer<Foo>[] comparers;
    public CompositeFooComparer(params IEqualityComparer<Foo>[] comparers)
    {
        this.comparers = comparers;
    }

    public bool Equals(Foo x, Foo y)
    {
        foreach (var comparer in comparers)
        {
            if (!comparer.Equals(x, y))
            {
                return false;
            }
        }
        return true;
    }

    public int GetHashCode(Foo obj)
    {
        var hash = 0;
        foreach (var comparer in comparers)
        {
            hash = hash * 17 + (comparer.GetHashCode(obj));
        }
        return hash;
    }
}

然后你可以像这样创建和使用它:

var fooA = new Foo
{
    Bar = 5,
    Day = Day.Fri,
    Name = "a"
};

var fooB = new Foo
{
    Bar = 5,
    Day = Day.Fri,
    Name = "b"
};

var barComparer = new FooBarComparer();
var dayComparer = new FooDayComparer();
var compositeComparer = new CompositeFooComparer(barComparer, dayComparer);

Console.WriteLine(compositeComparer.Equals(fooA, fooB)); // displays "true"

另一个想法是有一个比较器确实知道将比较哪些字段,而不是基于 bool 参数。

public class ConfigurableFooComparer : IEqualityComparer<Foo>
{
    private readonly bool compareBar;
    private readonly bool compareName;
    private readonly bool compareDay;

    public ConfigurableFooComparer(bool compareBar, bool compareName, bool compareDay)
    {
        this.compareBar = compareBar;
        this.compareName = compareName;
        this.compareDay = compareDay;
    }

    public bool Equals(Foo x, Foo y)
    {
        if (ReferenceEquals(x, y))
        {
            return true;
        }
        if (x == null || y == null)
        {
            return false;
        }

        if (compareBar && x.Bar != y.Bar)
        {
            return false;
        }
        if (compareName && x.Name != y.Name)
        {
            return false;
        }
        if (compareDay && x.Day != y.Day)
        {
            return false;
        }

        return true;
    }

    public int GetHashCode(Foo obj)
    {
        unchecked
        {
            var hash = 0;

            if (compareBar)
            {
                hash = hash * 17 + obj.Bar.GetHashCode();
            }
            if (compareName)
            {
                hash = hash * 17 + (obj.Name == null ? 0 : obj.Name.GetHashCode());
            }
            if (compareDay)
            {
                hash = hash * 17 + obj.Day.GetHashCode();
            }

            return hash;
        }
    }

然后像这样使用它:

var barAndDayComparer = new ConfigurableFooComparer(compareBar: true, compareName: false, compareDay: true);
Console.WriteLine(barAndDayComparer.Equals(fooA, fooB));

关于C#:如何在检查相等性时评估一个对象的多个计算机类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52341265/

相关文章:

c# - 在回发期间 JavaScript 失去其功能

c# - Web 服务请求返回 null

C# Comparer.Default<short>.Compare 和 Comparer.Default<byte> 不返回 -1、0 或 1

c# - 为什么 IComparer 要求您定义 IComparer.Compare(Object x, Object y) 而不仅仅是 Compare(Object x, Object y)?

c# - 一种更简洁的方法来自动调用一个又一个方法?

c# - 帮助编写文件夹结构的算法

c# - Windows 7 Home Premium 是否允许 (File.Encrypt)?

c# - 用 AssemblyLoadContext 替换 .NET AppDomain

.net - 更新 EF 模型 : tables missing

c# - LINQ orderby 与 IComparer