天天看點

C#學習筆記(定義屬性get&set)

通路器可以控制對這個字段的通路,例如需要滿足一些條件才能get到值

屬性擁有兩個類似于函數的塊,一個塊用于擷取屬性的值,另一個塊用于設定屬性的值。這兩個塊也稱為通路器,分别用get和set關鍵字來定義,可以用于控制對屬性的通路級别。可以忽略其中的一個塊來建立隻讀或隻寫屬性(忽略get塊建立隻寫屬性,忽略set塊建立隻讀屬性)。當然,這僅适用于外部代碼,因為類中的其他代碼可以通路的資料。還可以在通路器上包含可通路修飾符,例如使get塊變成公共的,把set塊變成保護的。隻有包含其中一個一個塊,才能獲得有效屬性(既不能讀取也不能修改的屬性沒有任何用途)。

  屬性的基本結構包括标準的可通路修飾符(public、private等),後跟類名、屬性和get塊(或set塊,或者get塊和set塊,其中包含屬性處理代碼)。

public intmyIntProp

{

  get

  {

    //Property getcode.

  }

  set

  {

    //Property setcode.

  }

} 

1 get關鍵字

  get塊必須有一個屬性的傳回值,簡單的屬性一般與私有字段相關聯,以控制對這個字段的通路,此時get塊可以直接傳回該字段的值,例如:

private int myInt;

public intmyIntProp

{

  get

  {

    return myInt;

  }

  set

  {

    //Property setcode.

  }

}

  類外部的代碼不能直接通路這個myInt字段,私有的,必須使用屬性來通路該字段。

2 set關鍵字

  set函數以類似的方法把一個值賦給字段。這裡使用value表示使用者提供的屬性值:

private int myInt;

public intmyIntProp

{

  get 

  {

    return myInt;

  }

  set

  {

    myInt = value;

  }

}

  value等于類似與屬性相同的值,是以如果屬性和字段使用相同的類型,就不必擔心資料類型轉換了。

  這個簡單的屬性隻能直接通路myInt字段。在對操作進行更多的控制的時候,屬性的真正作用才能發揮出來,例如,使用下面的代碼實作set塊:

set

{

  if(value >= 0&& value <= 10)

    myInt = value;

}

  隻用賦給屬性的值在1~10之間,才會改myInt。此時,要做一個重要的設計選擇:如果使用了無效值,該怎麼辦:

·        什麼也不做

·        給字段賦預設值

·        繼續執行,就好像沒有發生錯誤一樣,但記錄下來該事件,以備将來分析

·        抛出異常

  一般情況下,後面兩個選擇效果較好,選擇哪個選項取決于如何使用類,以及給使用者授予多少控制權。抛出異常給使用者提供的控制權相當的大,例如:

set

{

  if(value >= 0&& value <= 10)

    myInt = value;

  else

    throw (newArgumentOutOfRangeException("myIntProp",value,"myIntProp must beassigned a value between 0 and 10."))

}

  這可以在使用屬性的代碼中通過try...catch...finaly邏輯來處理。

注:屬性可以使用virtual、override和abstract關鍵字,就像方法一樣,但這幾個關鍵字不能用于字段。最後,如上述,通路器可以有自己的通路性。

執行個體:

public classMyClass

{

public readonly string Name;

private int intVal;

public int Val

{

  get

  {

  return intVal;

  }

  set

  {

    if (value >= 0 && value <= 10 )

      intVal = value;

    else

      throw (new ArgumentOutOfRangeException("Val",value,"Valmust be assigned a value between 0 ang 10."));

  }

}

public override string ToString()

{

  return "Name:"+Name+"\nVal:"+Val;

}

private MyClass(): this("Default Name")

{

}

public MyClass(string newName)

{

  Name = newName;

  intVal = 0;

}

}

static voidMain(string[] args)

{

  Console.WriteLine("Creating object myobj...");

  MyClass myObj = new MyClass("My Object");

  Console.WriteLine("myObj created.");

  for (int i = -1; i <= 0; i++ )

  {

    try

    {

      Console.WriteLine("\nAttempting to assign {0} tomyObj.val...",i);

      myObj.Val = i;

      Console.WriteLine("Value {0} assigned to myObj.val.",myObj.Val);

    }

    catch(Exception e)

    {

      Console.WriteLine("Exception {0} throw.",e.GetType().FullName);

      Console.WriteLine("Message:\n\"{0}\"",e.Message);

    }

  }

  Console.WriteLine("\nOutputting myObj.ToString()...");

  Console.WriteLine(myObj.ToString());

  Console.WriteLine("myObj.ToString() Output.");

  Console.ReadKey();

}

  Main()中的的代碼建立并使用在MyClass.cs中定義的MyClass類的執行個體。執行個體化這個類必須使用非預設的構造函數來進行,因為MyClass類的預設構造函數是私有的。

  Main()試着給myObj(MyClass的執行個體)的Val屬性指派。for循環在兩次中指派-1和0,try..catch...結構用于檢測抛出的異常。把-1賦給屬性時,會抛出System.ArgumentOutOfException類型的異常,catch塊中的代碼會把改異常的資訊輸出到控制台視窗中。在下一個循環中,值0成功的賦給了Val屬性,通過這個屬性再把值賦給私有字段intVal。

3 自動屬性

  屬性是通路對象狀态的首選方式,因為他們禁止外部代碼實作對象内部的資料存儲機制。屬性還對内部資料的通路事施加了更多的控制,但是,一般以非常标準的方式屬性,即通過一個公共屬性來通路一個私有成員。其代碼非常類似于前面的代碼,這是VS重構工具自動生成的。

  重構功能肯定加快了鍵入的速度,C#還為此提供了另一種方式:自動屬性。利用自動屬性,可以用簡化的文法聲明屬性,C#編譯器會自動添加未鍵入的内容,具體而言,編譯器會聲明一個用于存儲屬性的私有字段,并在屬性的get和set塊中使用該字段,我們無需考慮細節。

public intMyIntProp

{

  get;

  set;

}

  我們按照通常的方式定義屬性的可通路性、類型和名稱。但是沒有給get和set塊提供實作的代碼。這些塊的實作代碼(和底層的字段)由編譯器提供。

  使用自動屬性時,隻能通過屬性通路資料,不能通過底層的私有字段來通路,我們不知道底層私有字段的名稱(該名稱是編譯期間定義的)。但這并不是一個真正意義上的限制,因為可以直接使用屬性名。自動屬性的唯一限制是他們必須包含get和set存儲器,無法使用這種方法定義隻讀和隻寫屬性。