Перегрузка == оператор для класса, содержащего только строковые атрибуты
Каков наилучший (самый элегантный или эффективный) способ перегрузки оператора равенства в классе, содержащем только строковые атрибуты?
Пример:
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; }
}
Я знаю, как перегрузить самого оператора, однако меня интересуют следующие моменты:
- Есть ли способ элегантно сравнить такие два объекта (например, без необходимости писать
if
утверждение, содержащее взаимные сравнения всех атрибутов - Что было бы хорошей реализацией
GetHashCode()
метод в таком случае
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
но отражение ИМО здесь излишне.
Не говоря уже о том, что это "лучшее" или самое элегантное решение, но я бы имел тенденцию использовать массив и инициализатор индекса, используя перечисление, так что я мог бы повторно использовать get и установить логику и в этом случае сбросить хеш-код для быстрого первого сравнения. Преимущество перечисления состоит в том, что вам не нужно перепроверять логику сравнения при добавлении атрибута, и вы можете избежать дополнительных затрат на рефлексию.
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
}