[C#]Effective C# 條款八: 確保0為值類型的有效狀態

  • 14649
  • 0
  • C#
  • 2011-02-09

[C#]Effective C# 條款八: 確保0為值類型的有效狀態

.NET程式在物件初始時,變數初始器會將成員變數做初始化的動作。對於值類型的成員變數來說,會被初始為0值。因此我們應將0視為值類型的默認值。

 

以列舉型別來看,假設今天我有一個列舉型別:

	enum Sex
    {
        Boy=1,
        Girl=2
    }

 

 

 

其列舉值並未從0,而是從1開始。則初始值0對該列舉來說,是一個無效的狀態。程式也可能因此無法正常運作。像是:

	class Program
    {
        static void Main(string[] args)
        {
            Person p=new Person();
            //p.Sex = Sex.Boy;
            Console.WriteLine(p.Sex.ToString ());        
        }
    }
    enum Sex
    {
        Boy = 1,
        Girl = 2
    }
    struct Person
    {
        public String Name;
        public Sex Sex ;
    }

 

 

 

運行結果如下:

image

 

但在正常的情況下,列舉值應該要在列舉範圍內,運行結果應顯示如下這般:

image

 

這樣的問題我們無法透過建構子給予初始值來解決,因為就算指定了具備參數的建構子。

	struct Person
    {
        public String Name;
        public Sex Sex ;
        public Person(String name,Sex sex)
        {
            this.Name = name;
            this.Sex = sex;
        }
    }

 

 

 

 

 

 

 

對於值類型來說仍有預設建構子可以使用。像是:

	class Program
    {
        static void Main(string[] args)
        {
            Person p=new Person();
            Console.WriteLine(p.Sex.ToString ());        
        }
    }
    enum Sex
    {
        Boy = 1,
        Girl = 2
    }

    struct Person
    {
        public String Name;
        public Sex Sex;

        public Person(String name, Sex sex)
        {
            this.Name = name;
            this.Sex = sex;
        }
    }

 

 

且值類型的預設建構子無法自行撰寫,若嘗試撰寫編譯器會發出"Structs cannot contain explicit parameterless constructors"的錯誤。

image

 

而若想透過變數初始器來做設定的動作,編譯器也會以"cannot have instance field initializers"錯誤告知。

image

 

 

 

 

因此我們在使用值類型時特別留意其初始值,確保0為值類型的有效狀態,避免上述問題的發生。就像這樣:

	class Program
    {
        static void Main(string[] args)
        {
            Person p=new Person();
            Console.WriteLine(p.Sex.ToString ());        
        }
    }
    enum Sex
    {
        NotSet = 0,
        Boy = 1,
        Girl = 2
    }

    struct Person
    {
        public String Name;
        public Sex Sex;

        public Person(String name, Sex sex)
        {
            this.Name = name;
            this.Sex = sex;
        }
    }

 

 

除此之外,當撰寫設有Flags屬性的列舉型別,我們也要特別留意。除必須確保初始值0為有效狀態外,還需讓其值為沒有設定任何標記的狀態。像是:

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

 

 

 

這是因為設有Flags屬性的列舉型態,我們可能會拿來做像下面這樣的運算:

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

 

 

當Flat是0的話,判斷式依舊為false,達不到預期的效果。不過,這例子只是告知建議遵守該條款的原因。事實上,這樣的問題可以像下面這樣避開:

	if((flag & Styles.Flat) == Styles.Flat)
    DoFlatThings();