重载==仅包含字符串属性的类的运算符

本文关键字:运算符 属性 字符串 包含 重载 | 更新日期: 2023-09-27 18:00:43

在只包含字符串属性的类上重载相等运算符的最佳(最优雅或性能最好)方法是什么?

示例:

class MagicClass
{
    public string FirstAttribute { get; set; }
    public string SecondAttribute { get; set; }
    public string ThirdAttribute { get; set; }
    public string FourthAttribute { get; set; }
    public string FifthAttribute { get; set; }
}

我知道如何超载运营商本身,然而,我想知道以下几点:

  1. 有没有一种方法可以优雅地比较这两个对象(例如,不必编写包含所有属性的相互比较的if语句
  2. 在这种情况下,GetHashCode()方法的良好实现是什么

重载==仅包含字符串属性的类的运算符

这样做怎么样,只需创建所有属性的数组和一个循环。

internal class MagicClass
{
    public string FirstAttribute { get; set; }
    public string SecondAttribute { get; set; }
    public string ThirdAttribute { get; set; }
    public string FourthAttribute { get; set; }
    public string FifthAttribute { get; set; }
    private string[] AllProperties//Array of all properties
    {
        get
        {
            return new[]
            {
                FirstAttribute,
                SecondAttribute,
                ThirdAttribute,
                FourthAttribute,
                FifthAttribute
            };
        }
    }
    protected bool Equals(MagicClass other)
    {
        var thisProps = this.AllProperties;
        var otherProps = other.AllProperties;
        return thisProps.SequenceEqual(otherProps);
    }
    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((MagicClass) obj);
    }
    public override int GetHashCode()
    {
        unchecked
        {
            var thisProps = this.AllProperties;
            int hashCode = 0;
            foreach (var prop in thisProps)
            {
                hashCode = (hashCode * 397) ^ (prop != null ? prop.GetHashCode() : 0);
            }
            return hashCode;
        }
    }
}

然后,您可以在运算符重载中调用Equals方法。如果你懒得创建AllProperties数组,你可以使用Reflection,但IMO反射在这里太过分了。

并不是说这是"最好的"或最优雅的解决方案,但我倾向于使用数组和索引初始值设定项,使用枚举,这样我就可以重用get和set逻辑,在这种情况下,还可以重置哈希码以进行快速的第一次比较。枚举的优点是,添加属性时不必重新检查比较逻辑,并且可以防止诉诸反射的开销。

class MagicClass
{
    string[] Values = new string[Enum.GetValues(typeof(MagicClassValues)).Length];
    public string this[MagicClassValues Value] //and/or a GetValue/SetValue construction
    {
        get
        {
            return Values[(int)Value];
        }
        set
        {
            Values[(int)Value] = value;
            hash = null;
        }
    }
    int? hash; //buffered for optimal dictionary performance and == comparisson
    public override int GetHashCode()
    {
        if (hash == null)
            unchecked
            {
                hash = Values.Sum(s => s.GetHashCode());
            }
        return hash.Value;
    }
    public static bool operator ==(MagicClass v1, MagicClass v2) //used == operator, in compliance to the question, but this would be better for 'Equals'
    {
        if(ReferenceEquals(v1,v2))return true;
        if(ReferenceEquals(v1,null) || ReferenceEquals(v2,null) || v1.GetHashCode() != v2.GetHashCode())return false;
        return v1.Values.SequenceEqual(v2.Values);
    }
    public static bool operator !=(MagicClass v1, MagicClass v2)
    {
        return !(v1 == v2);
    }
    //optional, use hard named properties as well
    public string FirstAttribute { get { return this[MagicClassValues.FirstAttribute]; } set { this[MagicClassValues.FirstAttribute] = value; } }
}
public enum MagicClassValues
{
    FirstAttribute,
    SecondAttribute,
    //etc
}