這樣,Code #01 的第三行就可以工作了。值得提醒的是,Red、Green 和 Blue 等成員的值都是不變的,為了不讓客戶代碼修改它們的值,我把它們設成 readonly(注意:它們不可以設為 const,你知道為什麼嗎?)。另外,它們應該屬於 Color 類而不是某個實例的,於是把它們設成 static。
接著,Code #01 的第四行說明了 Color 的實例可以強制轉換成字符串,這可以通過重載轉換運算符做到:
// Code #03
public static explicit Operator string(Color value)
{
return value.m_Value;
}
與 Code #01 的第四行對應的是 Code #01 的第七行,它說明了字符串可以強制轉換成 Color 實例,這也是通過重載轉換運算符做到的:
// Code #04
public static explicit Operator Color(string value)
{
switch (value)
{
case "#FF0000":
return Red;
case "#00FF00":
return Green;
case "#0000FF":
return Blue;
default:
throw new InvalidCastException();
}
}
很明顯,並不是所有的字符串都可以轉換成 Color 實例,所以,當客戶代碼試圖把一個含有非預期值的字符串轉換成 Color 實例時就應該拋出 InvalidCastException 了。
誠然,有些人會對 Code #04 很反感,因為它裡面有一個 switch!當我們使用枚舉時,我們並不只是用它來進行一些值的轉換或者獲取其字面值,我們更希望用它來標識不同的情況或者類別,並根據枚舉實例的值來判斷屬於哪一情況或類別。換句話說,當我們決定使用枚舉時,我們就注定與條件語句結下不解之緣了。
最後,這裡給出 Color 的完整代碼:
// Code #05
Color#region Color
public class Color
{
private Color(string value)
{
m_Value = value;
}
public static explicit Operator Color(string value)
{
switch (value)
{
case "#FF0000":
return Red;
case "#00FF00":
return Green;
case "#0000FF":
return Blue;
default:
throw new InvalidCastException();
}
}
public static explicit Operator string(Color value)
{
return value.m_Value;
}
public override string ToString()
{
return m_Value;
}
public static readonly Color Red = new Color("#FF0000");
public static readonly Color Green = new Color("#00FF00");
public static readonly Color Blue = new Color("#0000FF");
private string m_Value;
}
#endregion
或許有人會提出這樣一個問題:我們經常會對枚舉進行判等運算,但為什麼 Code #05 中既沒有重載 Object.Equals 方法,也沒有提供 == 和 != 運算符呢?細心觀察 Color 的代碼,你會發現獲取 Color 的實例只有兩種途徑:通過靜態只讀字段和通過強制轉換運算符,但無論你是如何得到 Color 的實例,這些實例最終都是源自 Color 內部的靜態只讀字段。換言之,通過這兩種途徑分別獲得的兩個 Color 實例其實是同一個實例。