CA1036:必須在 Comparable 型別中覆寫方法
型別名稱 |
OverrideMethodsOnComparableTypes |
CheckId |
CA1036 |
分類 |
Microsoft.Design |
中斷變更 |
中斷 |
原因
公用或保護的型別會實作 System.IComparable 介面,而且未覆寫 Object.Equals,或未多載等號比較、不等比較、小於比較或大於比較的語言特定運算子。 如果型別只繼承介面的實作,此規則就不會報告違規。
規則描述
定義自訂排序次序的型別會實作 IComparable 介面。 CompareTo 方法會傳回整數值,表示兩個型別執行個體的正確排序次序。 此規則會識別設定排序次序的型別。這表示不套用等號比較、不等比較、小於比較或大於比較的一般意義。 當您提供 IComparable 的實作時,通常還必須覆寫 Equals,以便傳回與 CompareTo 一致的值。 如果您會覆寫 Equals,而且是以支援運算子多載的語言進行編碼,則必須同時提供與 Equals 一致的運算子。
如何修正違規
若要修正此規則的違規情形,請覆寫 Equals。 如果您的程式語言可支援運算子多載,請提供下列運算子:
op_Equality
op_Inequality
op_LessThan
op_GreaterThan
在 C# 中,用於代表這些運算子的語彙基元如下所示:==、!=、< 和 >。
隱藏警告的時機
在 Visual Basic .NET 中,當違規原因為遺失運算子且程式語言不支援運算子多載時,您就可以放心地隱藏這項規則的警告。 如果您判斷在應用程式內容中實作運算子不具意義,當這項規則的警告會在 op_Equality 以外的等號比較運算子上引發時,隱藏該警告也是安全的。 但是,如果您覆寫 Object.Equals,就永遠都要覆寫 op_Equality 和 == 運算子。
範例
下列範例會包含正確實作 IComparable 的型別。 程式碼註解會識別滿足與 Equals 和 IComparable 介面相關之各種規則的方法。
using System;
using System.Globalization;
namespace DesignLibrary
{
// Valid ratings are between A and C.
// A is the highest rating; it is greater than any other valid rating.
// C is the lowest rating; it is less than any other valid rating.
public class RatingInformation : IComparable, IComparable<RatingInformation>
{
public string Rating
{
get;
private set;
}
public RatingInformation(string rating)
{
if (rating == null)
{
throw new ArgumentNullException("rating");
}
string v = rating.ToUpper(CultureInfo.InvariantCulture);
if (v.Length != 1 || string.Compare(v, "C", StringComparison.Ordinal) > 0 || string.Compare(v, "A", StringComparison.Ordinal) < 0)
{
throw new ArgumentException("Invalid rating value was specified.", "rating");
}
this.Rating = v;
}
public int CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
RatingInformation other = obj as RatingInformation; // avoid double casting
if (other == null)
{
throw new ArgumentException("A RatingInformation object is required for comparison.", "obj");
}
return this.CompareTo(other);
}
public int CompareTo(RatingInformation other)
{
if (object.ReferenceEquals(other, null))
{
return 1;
}
// Ratings compare opposite to normal string order,
// so reverse the value returned by String.CompareTo.
return -string.Compare(this.Rating, other.Rating, StringComparison.OrdinalIgnoreCase);
}
public static int Compare(RatingInformation left, RatingInformation right)
{
if (object.ReferenceEquals(left, right))
{
return 0;
}
if (object.ReferenceEquals(left, null))
{
return -1;
}
return left.CompareTo(right);
}
// Omitting Equals violates rule: OverrideMethodsOnComparableTypes.
public override bool Equals(object obj)
{
RatingInformation other = obj as RatingInformation; //avoid double casting
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.CompareTo(other) == 0;
}
// Omitting getHashCode violates rule: OverrideGetHashCodeOnOverridingEquals.
public override int GetHashCode()
{
char[] c = this.Rating.ToCharArray();
return (int)c[0];
}
// Omitting any of the following operator overloads
// violates rule: OverrideMethodsOnComparableTypes.
public static bool operator ==(RatingInformation left, RatingInformation right)
{
if (object.ReferenceEquals(left, null))
{
return object.ReferenceEquals(right, null);
}
return left.Equals(right);
}
public static bool operator !=(RatingInformation left, RatingInformation right)
{
return !(left == right);
}
public static bool operator <(RatingInformation left, RatingInformation right)
{
return (Compare(left, right) < 0);
}
public static bool operator >(RatingInformation left, RatingInformation right)
{
return (Compare(left, right) > 0);
}
}
}
下列應用程式會測試先前所示之 IComparable 實作的行為。
using System;
namespace DesignLibrary
{
public class Test
{
public static void Main(string [] args)
{
if (args.Length < 2)
{
Console.WriteLine ("usage - TestRatings string 1 string2");
return;
}
RatingInformation r1 = new RatingInformation(args[0]) ;
RatingInformation r2 = new RatingInformation( args[1]);
string answer;
if (r1.CompareTo(r2) > 0)
answer = "greater than";
else if (r1.CompareTo(r2) < 0)
answer = "less than";
else
answer = "equal to";
Console.WriteLine("{0} is {1} {2}", r1.Rating, answer, r2.Rating);
}
}
}