這個做法在說明 implicit
與 explicit
operator 在轉型中的應用場景與可能會導致錯誤發生時很難找到問題。
我們知道所有類型的基底類型都是 System.Object
,也就代表能夠將衍生的類型轉型回 System.Object
,這樣就能在某些需要傳入 Object 類型的方法
改用其他類型來替換 Object,這個就是使用 polymorphism 的特性來達到替換的功能。
例如下面的 Object.Equals
方法,就能夠直接傳入 int 類型進行替換。
void Main()
{
int i = 1;
int j = 1;
Console.WriteLine(Object.Equals(i, j));
}
下面這段程式碼建立了兩個衍生類型 Car
與 Bus
,這兩個類型有相關性可以說 Bus
是 Car
的一種特例,也就是說我們可以寫一個傳入 Car
類型方法 MoveForward
就可以與 Bus
一起共用這個方法,但是這兩個類別並沒有直接的繼承關係所以要透過 implicit
或 explicit
operator 來達到這個需求。
void Main()
{
Bus bus1 = new Bus(3);
MoveForward(bus1);
Console.WriteLine(bus1);
}
public static void MoveForward(Car car)
{
car.Distance = 100;
}
public class Car : Vehicle
{
private int _passenger;
public int Distance { get; set; }
public int Passenger
{
get { return _passenger; }
set
{
if (value > 3)
throw new ArgumentException("Too Many People");
_passenger = value;
}
}
public Car(int passenger)
{
Passenger = passenger;
}
//public Car(Bus bus)
//{
// Passenger = bus.Passenger;
//}
public static implicit operator Bus(Car car)
{
return new Bus(car.Passenger);
}
}
public class Bus : Vehicle
{
private int _passenger;
public int Distance { get; set; }
public int Passenger
{
get { return _passenger; }
set { _passenger = value; }
}
public Bus(int passenger)
{
Passenger = passenger;
}
public static implicit operator Car(Bus bus)
{
return new Car(bus.Passenger);
}
}
public class Vehicle {}
但這段程式碼有一個問題就是在執行 implicit operator Car
這段邏輯的時候會建立一個新的 Car
物件,這裡把它稱之為中間物件,
這會導致 MoveForward 方法修改的是這個中間物件的屬性而不是 bus1
,這就會導致中間物件產生之後被修改然後就直接被回收了,
並且這段程式碼可讀性也不是非常好,也很難排查問題。
並且可以看出它的關鍵邏輯就是幫你呼叫建構函式而已,那其實跟我們自己多載一個新的建構函式一模一樣,修改後的程式碼如下。
void Main()
{
Bus bus1 = new Bus(3);
Car car1 = new Car(bus1);
MoveForward(car1);
Console.WriteLine(car1);
}
這種方式也會產生中間物件,但並不會丟失修改的狀態也不會被直接回收,而且表達的語意也比較明確好懂,就是透過多載建構函式就能達到一樣的效果。
Summary
這個做法在說明 implicit
與 explicit
operator 雖然可以讓你的轉型程式碼更加簡潔,但也更難排除問題,
並且方法可能修改的只是中間物件導致狀態遺失,這種問題在大型的應用程式中不好排查,而且透過多載建構函是也能達到同樣的效果,所以不建議用這兩個 operator。