CA1013: перегружайте оператор равенства при перегрузке сложения и вычитания
TypeName |
OverloadOperatorEqualsOnOverloadingAddAndSubtract |
CheckId |
CA1013 |
Категория |
Microsoft.Design |
Критическое изменение |
Не критическое |
Причина
Открытый или защищенный тип реализует операторы сложения или вычитания без реализации оператора равенства.
Описание правила
Если экземпляры типа можно сочетать при помощи таких операций как сложение и вычитание, нужно почти всегда определять операцию равенства, которая должна возвращать значение true для любых двух экземпляров с одинаковыми составляющими значениями.
Заданный по умолчанию оператор равенства нельзя использовать в перегруженной реализации оператора равенства. Это может привести к переполнению стека. Для реализации оператора равенства воспользуйтесь методом Object.Equals. См. следующий пример.
If (Object.ReferenceEquals(left, Nothing)) Then
Return Object.ReferenceEquals(right, Nothing)
Else
Return left.Equals(right)
End If
if (Object.ReferenceEquals(left, null))
return Object.ReferenceEquals(right, null);
return left.Equals(right);
Устранение нарушений
Чтобы исправить нарушение этого правила, реализуйте оператор равенства, чтобы он был математически однородным с операторами сложения и вычитания.
Отключение предупреждений
Можно безопасно отключать предупреждения этого правила, если заданная по умолчанию реализация оператора равенства обеспечивает его правильную работу для заданного типа.
Пример
В следующем примере определяется тип (BadAddableType), нарушающий это правило. Этот тип должен реализовать оператор равенства, чтобы любые два экземпляра с одинаковыми значениями полей выдавали значение true для равенства. Тип GoodAddableType демонстрирует исправленную реализацию. Обратите внимание, что этот тип также реализует оператор неравенства и переопределяет Equals для выполнения других правил. При полной реализации также потребуется реализовать GetHashCode.
using System;
namespace DesignLibrary
{
public class BadAddableType
{
private int a, b;
public BadAddableType(int a, int b)
{
this.a = a;
this.b = b;
}
// Violates rule: OverrideOperatorEqualsOnOverridingAddAndSubtract.
public static BadAddableType operator +(BadAddableType a, BadAddableType b)
{
return new BadAddableType(a.a + b.a, a.b + b.b);
}
// Violates rule: OverrideOperatorEqualsOnOverridingAddAndSubtract.
public static BadAddableType operator -(BadAddableType a, BadAddableType b)
{
return new BadAddableType(a.a - b.a, a.b - b.b);
}
public override string ToString()
{
return String.Format("{{{0},{1}}}", a, b);
}
}
public class GoodAddableType
{
private int a, b;
public GoodAddableType(int a, int b)
{
this.a = a;
this.b = b;
}
// Satisfies rule: OverrideOperatorEqualsOnOverridingAddAndSubtract.
public static bool operator ==(GoodAddableType a, GoodAddableType b)
{
return (a.a == b.a && a.b == b.b);
}
// If you implement ==, you must implement !=.
public static bool operator !=(GoodAddableType a, GoodAddableType b)
{
return !(a==b);
}
// Equals should be consistent with operator ==.
public override bool Equals(Object obj)
{
GoodAddableType good = obj as GoodAddableType;
if (obj == null)
return false;
return this == good;
}
public static GoodAddableType operator +(GoodAddableType a, GoodAddableType b)
{
return new GoodAddableType(a.a + b.a, a.b + b.b);
}
public static GoodAddableType operator -(GoodAddableType a, GoodAddableType b)
{
return new GoodAddableType(a.a - b.a, a.b - b.b);
}
public override string ToString()
{
return String.Format("{{{0},{1}}}", a, b);
}
}
}
В следующем примере проверяется равенство с помощью экземпляров типов, которые были определены раннее в этом разделе, для демонстрации правильного поведения оператора равенства.
using System;
namespace DesignLibrary
{
public class TestAddableTypes
{
public static void Main()
{
BadAddableType a = new BadAddableType(2,2);
BadAddableType b = new BadAddableType(2,2);
BadAddableType x = new BadAddableType(9,9);
GoodAddableType c = new GoodAddableType(3,3);
GoodAddableType d = new GoodAddableType(3,3);
GoodAddableType y = new GoodAddableType(9,9);
Console.WriteLine("Bad type: {0} {1} are equal? {2}", a,b, a.Equals(b)? "Yes":"No");
Console.WriteLine("Good type: {0} {1} are equal? {2}", c,d, c.Equals(d)? "Yes":"No");
Console.WriteLine("Good type: {0} {1} are == ? {2}", c,d, c==d? "Yes":"No");
Console.WriteLine("Bad type: {0} {1} are equal? {2}", a,x, a.Equals(x)? "Yes":"No");
Console.WriteLine("Good type: {0} {1} are == ? {2}", c,y, c==y? "Yes":"No");
}
}
}
После выполнения примера получается следующий результат.