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

时间:2014-04-28 11:51:49

标签: c# string comparison operator-overloading gethashcode

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

示例:

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()方法的良好实现

2 个答案:

答案 0 :(得分:2)

这样的事情,只需创建所有属性的数组和循环。

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反射在这里有点过分。

答案 1 :(得分:0)

不是说这是最好的'或者最优雅的解决方案,但是我倾向于使用数组和索引初始化程序,使用枚举,因此我可以重用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
}