Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得
本節提出利用泛型限制表達式簡化程式碼,設計剛剛好符合需求的 API;過多或過少的限制都會造成客戶端使用上的問題,包含不明確的呼叫或是過多的限制。
1. 利用泛型限制表達式設計簡潔的 API。
考慮需要設計一個判斷兩個物件是否相等的 API,輸入參數型別為泛型。
設計方法一:
public static bool areEqual<T>( T left, T right )
{
if ( left == null )
return right == null;
var leftVal = left as IComparable<T>;
if ( leftVal != null )
{
if ( right is IComparable<T> )
return leftVal.CompareTo( right ) == 0;
else
throw new ArgumentException( "Type does not implement IComparable<T>.",
nameof( right ) );
}
// Failure.
else
{
throw new ArgumentException( "Type does not implement IComparable<T>.",
nameof( left ) );
}
}
這樣子的設計有幾項缺點:
a. 重覆的程式碼(擲出例外)。
b. 巢狀的 if - else 判斷式。
c. 無法在編譯時期檢查到錯誤(必須等到執行階段判斷輸入型別是否有實作 IComparable<T>)。
用泛型限制表達式重構。
設計方法二:
public static bool areEqual2<T>( T left, T right ) where T : IComparable<T>
=> left.CompareTo( right ) == 0;
程式碼明顯簡潔許多,這樣設計有幾項優點:
a. 沒有重複的程式碼。
b. 移除了所有 if - else 判斷式。
c. 在編譯時期就可以檢查輸入型別有無實作 IComparable<T>。
2. 利用泛型限制表達式限制剛剛好的設計,不多不少。
考慮以下程式碼:
public static bool areEqual<T>( T left, T right )
=> left.Equals( right );
這樣的寫法需要考慮到當輸入型別為值型別時,會產生裝箱操作( System.Object.Equals)。
為了避免多餘的操作,可以限制 T 需實作的介面。
public static bool areEqual<T>( T left, T right ) where T : IEquatable<T>
=> left.Equals( right );
如此一來,客戶端必須實作 IEquatable<T> 才能正常編譯程式;且不會發生裝箱操作。
Note:泛型限制表達式是兩面刃;當限制越多,使用上就會更不方便。在這個例子裡,也需考慮是否要為了值型別而額外撰寫程式碼(客戶端需實作 IEquatable<T>)。
結論:
1. 善加利用泛型限制表達式設計 API。
2. 仔細考慮限制的範圍是否符合需求。
1. 善加利用泛型限制表達式設計 API。
2. 仔細考慮限制的範圍是否符合需求。