程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Effective C#原則28:避免轉換操作(1)

Effective C#原則28:避免轉換操作(1)

編輯:關於C語言

轉換操作是一種等代類型(Substitutability)間操作轉換操作。等代類型就 是指一個類可以取代另一個類。這可能是件好事:一個派生類的對象可以被它基 類的一個對象取代,一個經典的例子就是形狀繼承。先有一個形狀類,然後派生 出很多其它的類型:長方形,橢圓形,圓形以及其它。你可以在任何地方用圖形 狀來取代圓形,這就是多態的等代類型。這是正確的,因為圓形就是一個特殊的 形狀。當你創建一個類時,明確的類型轉化是可以自動完成的。正如.Net中類的 繼承,因為System.Object是所有類型的基類,所以任何類型都可以用 System.Obejct來取代。同樣的情況,你所創建的任何類型,也應該可以用它所 實現的接口來取代,或者用它的基類接口來取代,或者就用基類來取代。不僅如 此,C#語言還支持很多其它的轉換。

當你為某個類型添加轉換操作時, 就等於是告訴編譯器:你的類型可以被目標類所取代。這可能會引發一些潛在的 錯誤,因為你的類型很可能並不能被目標類型所取代(譯注:這裡並不是指繼承 關系上的類型轉換,而是C#語言許可我們的另一種轉換,請看後文)。它所的副 作用就是修改了目標類型的狀態後可能對原類型根本無效。更糟糕的是,如果你 的轉換產生了臨時對象,那麼副作用就是你直接修改了臨時對象,而且它會永久 丟失在垃圾回收器。總之,使用轉換操作應該基於編譯時的類型對象,而不是運 行時的類型對象。用戶可能須要對類型進行多樣化的強制轉換操作,這樣的實際 操作可能產生不維護的代碼。

你可以使用轉換操作把一個未知類型轉化 為你的類型,這會更加清楚的表現創建新對象的操作(譯注:這樣的轉換是要創 建新對象的)。轉換操作會在代碼中產生難於發現的問題。假設有這樣一種情況 ,你創建了如圖3.1那樣的類庫結構。橢圓和圓都是從形狀類繼承下來的,盡管 你相信橢圓和圓是相關的,但還是決定保留這樣的繼承關系。這是因為你不想在 繼承關系中使用非抽象葉子類,這會在從橢圓類上繼承圓類時,有一些不好實現 的難題存在。然而,你又意識到每一個圓形應該是一個橢圓,另外某些橢圓也可 能是圓形。

(圖3.1)

(譯注:這一原則中作者所給出的例子不是很 恰當,而且作者也在前面假設了原因,因此請讀者不要對這個例子太鑽牛角尖, 理解作者所在表達的思想就行了,相信在你的C#開發中可能也會遇到類似的轉換 問題,只是不太可能從圓形轉橢圓。)

這將導致你要添加兩個轉換操作。 因為每一個圓形都是一個橢圓,所以要添加隱式轉換從一個圓形轉換到新的橢圓 。隱式轉換會在一個類要求轉化為另一個類時被調用。對應的,顯示轉化就是程 序員在代碼中使用了強制轉換操作符。

public class Circle : Shape
{
 private PointF _center;
 private float _radius;
 public Circle() :
  this ( PointF.Empty, 0 )
 {
 }
 public Circle( PointF c, float r )
 {
  _center = c;
  _radius = r;
 }
 public override void Draw()
 {
  //...
 }
 static public implicit Operator Ellipse( Circle c )
 {
  return new Ellipse( c._center, c._center,
   c._radius, c._radius );
 }
}

現在你就已經實現了隱式的轉換操作,你可 以在任何要求橢圓的地方使用圓形。而且這個轉換是自動完成的:

public double ComputeArea( Ellipse e )
{
 // return the area of the ellipse.
}
// call it:
Circle c = new Circle( new PointF( 3.0f, 0 ), 5.0f );
ComputeArea( c );

我只是想用這個例子表達可替代類型:一個圓形已經可以代替 一個可橢圓了。ComputeArea函數可以在替代類型上工作。你很幸運,但看下面 這個例子:

public void Flatten( Ellipse e )
{
  e.R1 /= 2;
 e.R2 *= 2;
}
// call it using a circle:
Circle c = new Circle( new PointF ( 3.0f, 0 ), 5.0f );
Flatten( c );

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved