程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> Effective C#原則8:確保0對於值類型數據是有效的

Effective C#原則8:確保0對於值類型數據是有效的

編輯:關於C#

.Net系統默認所有的對象初始化時都為0。這並沒有提供一個方法來預防其他 程序員創建的值類型數據的實例在初始化是都是0。請讓你的數據類型默認值也 是0。

一個特殊情況是在枚舉類型數據中。決不要創建一個不包括0在內 的枚舉類型。所有的枚舉類型都是從System.ValueType派生的。枚舉類型的值是 從0開始的,但你可以改變這一行為:

public enum Planet
{
 // Explicitly assign values.
 // Default starts at 0 otherwise.
 Mercury = 1,
 Venus = 2,
 Earth = 3,
 Mars = 4,
 Jupiter = 5,
 Saturn = 6,
 Neptune = 7,
 Uranus = 8,
 Pluto = 9
}
Planet sphere = new Planet();

sphere此時的值就是0,而這並不是一個有效的值。枚 舉類型的取值限制在所有列舉的值中,任何依懶這一(普通)事實的代碼都將無法 工作。當你為你的枚舉類型創建你自己的取值時,請確保0是當中的一個。如果 你的枚舉類型采用的是以位(bit)模式,把0定義為其它屬性不存在時的取值。

按照現在的情況,你迫使用戶必須精確的初始化值:

Planet sphere = Planet.Mars;

這將使包含 (Planet)這一類型的其它類型很難創建:

public struct ObservationData
{
 Planet  _whichPlanet; //what am I looking at?
 Double _magnitude; // perceived brightness.
}

創建一個新ObservationData實例的用戶會創建一個不合法的 Planet成員:

ObservationData d = new ObservationData ();

最後創建的ObservationData的成員_magnitude的值是0,這 是合理的。但_whichPlanet卻是無效的。你須要讓0也是有效的(狀態)。如果可 能,選擇把0做為一個最好的默認。Planet枚舉類型沒有一個明確的默認值,無 論用戶是否任意的選擇一些行星,這都不會給人留下好的感覺。當你陷入這樣的 情況時,使用0做為一個非初始化的值,這也是在後面可以更新的:

public enum Planet
{
 None = 0,
 Mercury = 1,
 Venus = 2,
 Earth = 3,
 Mars = 4,
  Jupiter = 5,
 Saturn = 6,
 Neptune = 7,
 Uranus = 8,
 Pluto = 9
}
Planet sphere = new Planet ();

此時,sphere具有一個(默認)值None。為Planet枚舉類型添 加的這個非初始化的默認值,對ObservationData結構。最新創建的 ObservationData對象的目標上具有None和一個數值0。添加一個清晰的構造函數 讓用戶為你的類型的所有字段明白的初始化:

public struct ObservationData
{
 Planet  _whichPlanet; //what am I looking at?
 Double _magnitude; // perceived brightness.
 ObservationData( Planet target,
  Double mag )
 {
  _whichPlanet = target;
  _magnitude = mag;
 }
}

但請記住,默認的構造函數還是可訪問的,而且是結構的部份。 用戶還是可以創建一個系統初始化的變量,而你無法阻止它。

在結束枚 舉類型轉而討論其它類型之前,你須要明白幾個用於標記的特殊枚舉類型規則。 枚舉類型在使用Flags特性時,必須把None的值設置為0:

[Flags]
public enum Styles
{
 None = 0,
 Flat = 1,
 Sunken = 2,
 Raised = 4,
}

很多開發 人員使用枚舉標記和位運算操作AND進行運行,0值會與位標記產生嚴重的問題。 下面這個實驗如果Flat的值是0時,是決不會成功的:

if ( ( flag & Styles.Flat ) != 0 ) // Never true if Flat == 0.
  DoFlatThings( );

如果你遇到Flags,確保0對它來說是有效的, 並且這就著:“對所有缺少的標記。”

另一個很常見的初始 化問題就是值類型中包含了引用類型。字符串是一個常見的例子:

public struct LogMessage
{
 private int _ErrLevel;
 private string _msg;
}
LogMessage MyMessage = new LogMessage( );

MyMessage包含了一個_msg為 null的引用字段。這裡沒有辦法強行使用另一個不同的初始化方法,但你利用屬 性來局部化這個問題。你創建一個屬性向所用的用戶暴露_Msg的值。添加一個業 務邏輯,使得當字符串為null引用是,用空 串來取而代之:

public struct LogMessage
{
 private int _ErrLevel;
 private string _msg;
 public string Message
 {
  get
  {
   return (_msg != null ) ?
    _msg : string.Empty;
  }
  set
  {
   _msg = value;
  }
 }
}

(譯注: 我個人覺得這裡違反了原則一。當對兩個實例進行賦值COPY時,會出現,你明明 使用了a=b的運行,但實際上a!=b的結果。可以參見原則1。)

在你自己的 數據類型內部,你應該添加這樣的一個屬性。做了這樣的局部處理後,null引用 在某一位置做了驗證。當調用是在你的程序集內時,Message的訪問器基本上是 可以很好的內聯的。你將會取得高效低錯的代碼。

系統為所有的值類型 數據初始化為0,而沒有辦法防止用戶在創建一個值類型實例時,給所有的值類 型都賦值為0。如果可能,把0設置為自然的默認值。特殊情況下,使用Flags特 性的枚舉類型必須確保0是所有缺省標記的值。

返回教程目錄

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