Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得
設計類別時,不只實作泛型版本,非泛型版本也應一起實作;以支援較舊版本。
public class NameTest :
IComparable<NameTest>,
IEquatable<NameTest>,
IComparable
{
public string First { get; set; }
public string Last { get; set; }
public string Middle { get; set; }
public static bool checkEquality( object left, object right ) =>
left?.Equals( right ) ?? ( right == null );
public static bool checkEquality<T>( T left, T right )
where T : IEquatable<T> =>
left?.Equals( right ) ?? ( right == null );
// 實作 IEquatable<NameTest>
public bool Equals( NameTest other )
{
if ( ReferenceEquals( this, other ) )
return true;
if ( ReferenceEquals( other, null ) )
return false;
return Last == other.Last &&
First == other.First &&
Middle == other.Middle;
}
// 需增加明確型別判斷,避免呼叫到 Equals( object ) 版本。
// NameTest 的子類別皆可轉型成 NameTest,但型別依然不同。
public override bool Equals( object obj ) =>
obj.GetType( ) == typeof( NameTest ) ? // Check Runtime Type.
Equals( obj as NameTest ) : false; // Cast to NameTest.
// 覆寫 ==,使之與 Equals( NameTest )結果相符。
public static bool operator ==( NameTest left, NameTest right ) =>
left?.Equals( right ) ?? ( right == null );
// 覆寫 !=,使之與 Equals( NameTest )結果相符。
public static bool operator !=( NameTest left, NameTest right ) =>
!left?.Equals( right ) ?? ( right != null );
// 實作 IComparable<NameTest>
public int CompareTo( NameTest other )
{
if ( ReferenceEquals( this, other ) )
return 0;
if ( ReferenceEquals( other, null ) )
return 1; // Any non-null object > null
var result = Last.CompareTo( other.Last );
if ( result != 0 )
return result;
result = First.CompareTo( other.First );
if ( result != 0 )
return result;
return Middle.CompareTo( other.Middle );
}
// 顯式定義 IComparable.CompareTo,避免呼叫非泛型版本。
// 須明確轉型為 IComparable 才能呼叫此方法。
int IComparable.CompareTo( object obj ) =>
obj.GetType( ) == typeof( NameTest ) ?
CompareTo( obj as NameTest ) :
throw new ArgumentException( "Argument is not a Name object." );
// 覆寫 <,使之與 CompareTo 結果相符。
public static bool operator <( NameTest left, NameTest right )
{
if ( left == null )
return right != null;
return left.CompareTo( right ) < 0;
}
// 覆寫 <=,使之與 CompareTo 結果相符。
public static bool operator <=( NameTest left, NameTest right )
{
if ( left == null )
return true;
return left.CompareTo( right ) <= 0;
}
// 覆寫 >,使之與 CompareTo 結果相符。
public static bool operator >( NameTest left, NameTest right )
{
if ( left == null )
return right == null;
return left.CompareTo( right ) > 0;
}
// 覆寫 >=,使之與 CompareTo 結果相符。
public static bool operator >=( NameTest left, NameTest right )
{
if ( left == null )
return right == null;
return left.CompareTo( right ) >= 0;
}
// 由於覆寫了 Equals( object ),也需覆寫 GetHashCode。
public override int GetHashCode( )
{
var hash = 0;
if ( Last != null )
hash = Last.GetHashCode( );
if ( First != null )
hash ^= First.GetHashCode( );
if ( Middle != null )
hash ^= Middle.GetHashCode( );
return hash;
}
}
結論:
1. 此節對目前工作內容上較無明確的關連,目前還是以基本比對居多。
2. 若實作了 IEquatable<T> 與 IComparable<T>,也需注意其運算子有無覆寫,以免得到不一致的結果。
3. 顯式定義 IComparable.CompareTo,避免呼叫到非泛型版本。
1. 此節對目前工作內容上較無明確的關連,目前還是以基本比對居多。
2. 若實作了 IEquatable<T> 與 IComparable<T>,也需注意其運算子有無覆寫,以免得到不一致的結果。
3. 顯式定義 IComparable.CompareTo,避免呼叫到非泛型版本。