15 使用屬性以訪問字段

1.什麼是屬性

定義:是字段和方法的交集—— 看起來像字段,用起來像方法。

訪問屬性所用的語法和訪問字段一樣。然而,編譯器會將這種字段風格的語法自動轉換成對特定訪問器的調用。

訪問器:取值和獻值方法統稱爲訪問器方法。兩個方法有時也稱爲get訪問器和set訪問器,或者getter 和setter。

屬性的聲明如下所示:

AccessModifier Type ProperName
{

    get
    {
        //取值代碼
    }

    set
    {
        //賦值代碼
    }

}

屬性可以包含兩個代碼塊,分別以get和set關鍵字開頭。其中,get 塊包含讀取屬性時執行的語句,set塊包含在向屬性寫入時執行的語句。屬性的類型指定了由get和set訪問器讀取和寫入的數據的類型。

 

屬性和字段名稱的注意事項:

例如一下代碼,它實現了名爲Employee的類。EmployeeID 屬性提供對私有字段employeeID字段的公共訪問,

class Employee
{

    private int employeeID;
    public int EmployeeID
    {

        get { return this. EmployeeID; }
        set { this. EmployeeID = value; }

    }

}

代碼編譯沒有問題,但每次訪問EmployeeID屬性都會拋出StackoverflowException異常,這是由於get和set訪問器不小心引用屬性(以大寫字母E開頭)而不是私有字段(小寫e),這造成了無限遞歸,最終造成可用內存被耗盡。這種bug是很難發現的!有鑑於此,我們以下劃線開頭命名爲屬性提供數據的私有字段。這樣可以更加明顯地和屬性進行區分。除此之外的其他所有私有字段還是使用不以下劃線開頭的camelCase 標識符。

 

1.1使用屬性

在表達式中使用屬性時,要麼從中取值,要麼向其賦值。下例從ScreenPosition結構的X和Y屬性中取值:

ScreenPosition origin=new ScreenPosition(e=0, 0);
int xpos =origin.x; // 實際調用origin.X. get
int ypos=origin.Y; // 實際調用origin.Y.get

注意,現在屬性和字段是用相同的語法來訪問。從屬性取值時,編譯器自動將字段風格的代碼轉換成對屬性的get訪問器的調用。類似地,向屬性賦值時,編譯器自動將字段風格的代碼轉換成對該屬性的set訪問器的調用:

origin.X=40;//實際調用origin.X.set. value 設爲40
origin.Y=100; //實際調用origin.Y.set, value 設爲100

如前所述,要賦的新值通過value變量傳給set訪問器。“ 運行時”自動完成傳值。

 

還可同時對屬性進行取值和賦值。在這種情況下,get和set訪問器都會被用到。例如,編譯器自動將以下語句轉換成對get和set訪問器的調用:

origin.X +=10;

提示:可採取和聲明靜態字段及方法一樣的方式聲 明靜態屬性。訪問靜態屬性時,要附加類或結構名稱作爲前綴,而不是附加類或結構的實例名稱作爲前綴。

 

1.2只讀屬性

可以聲明只包含get 訪問器的屬性,這稱爲只讀屬性。例如,以下代碼將ScreenPosition結構的X屬性聲明爲只讀屬性:

struct ScreenPosition
{

    private int. x;
    public int X
    {
        get { return this. X; }
    }

}

X屬性不含set訪問器,向X寫入會報告編譯時錯誤,例如:

origin.x =140; //編譯時錯誤

1.3只寫屬性

類似地,可聲明只包含set 訪問器的屬性,這稱爲只寫屬性。例如,以下代碼將ScreenPosition結構的x屬性聲明爲只寫屬性:

struct ScreenPosition
{

    private int. x;
    ...
    public int X
    {
        set { this. x = rangeCheckedX(value); }
    }

}

X屬性不包含get訪問器。所以,讀取X會報告編譯時錯誤,例如:

Console.WriteLine(origin.X);//編譯時錯誤
origin.X = 200; //編譯通過
origin.X += 18;//編譯時錯誤

注意:只寫屬性適合對密碼這樣的數據進行保護。理想情況下,實現了安全性的應用程

序允許設置密碼,但不允許讀取密碼。登錄時用戶要提供密碼。登錄方法將用戶提供的密碼與存儲的密碼比較,只返回兩者是否匹配的消息。

 

1.4屬性的可訪問性

聲明屬性時要指定可訪問性(public, private 或protected)。但在屬性聲明中,可爲get和set訪問器單獨指定可訪問性,從而覆蓋屬性的可訪問性。例如,下面這個版本的ScreenPosition結構將x和Y屬性的set訪問器定義成私有,而get訪問器仍爲公共(因爲屬性是公共的):

struct ScreenPosition
{

    private int _x, _y;
    …
    public int X
    {

        get { return this._x; }
        private set { this._x=rangeCheckedX(value); }

    }

    public int Y
    {

        get { return this._y; }
        private set { this._y=rangeCheckedY(value); }

    }
    …

}

爲兩個訪問器定義不同的可訪問性時,必須遵守以下規則。

(1)只能改變 一個訪問器的可訪問性。例如,將屬性聲明爲公共,但將它的兩個訪問器都聲明成私有是沒有意義的。

(2)訪問器 的訪問修飾符(也就是public, private或者protected)所指定的可訪問性在限制程度上必須大於屬性的可訪問性。例如,將屬性聲明爲私有,就不能將get訪問器聲明爲公共(相反,應該屬性公共,set訪問器私有)。

 

2.理解屬性的侷限性

屬性在外觀、 行爲和感覺上都像字段。但屬性本質上是方法而不是字段。另外,屬性存在以下限制。

(1)只有在結構或類初始化好之後,才能通過該結構或類的屬性來賦值。下例的代碼非法,因爲結構變量location尚未使用new來初始化:

ScreenPosition location;
location.X = 40; //編譯時錯誤,location 尚未賦值

(2)不能將屬性作爲ref或out參數值傳給方法:但可寫的字段能作爲ref或out參數值傳遞。這是由於屬性並不真正指向一個內存位置:相反,它指向的是一個訪問器方法,例如:

MyMethod(ref location.X); // 編譯時錯誤

(3)屬性最多隻能包含一個get和一個set訪問器。不能包含其他方法、字段或屬性。

(4)get和set訪問器不能獲取任何參數。要賦的值會通過內建的、隱藏的value變量自動傳給set訪問器。

(5)不能聲明const 屬性,例如:

const int X{ get { ... }set { ...} } //編譯時錯誤

 

3.在接口中聲明屬性

接口除了能定義方法,還能定義屬性。

例如:

interface IScreenPosition
{

    int X{get;set;}
    int Y{get;set;};

}

實現該接口的任何類或結構都必須實現X和Y屬性,並在屬性中定義get和set訪問器,例如:

class ScreenPositlon : IScreenPosition
{

    public int X
    {
        get{...}
        set{...}
    }

    public int Y
    {
        get{...}
        set{…}
    }
    …

}

用途:例如可以用屬性替代方法

 

4.生成自動屬性

C#語言的設計者知道程序員都是“大忙人”,不該花時間寫多餘的代碼。所以,C#編譯器現在能自動爲屬性生成代碼,如下所示:

class Circle
{

    public int Radius{ get; set; }
    …

}

在這個例子中,Circle 類包含名爲Radius的屬性。除了屬性的類型,不必指定這個屬性是如何工作的一get 和set訪問器都是空白的。C#編譯器自動將這個定義轉換成私有字段以及一個默認的實現,如下所示:

class Circle
{

    private int _radius;
    public int Radius{
        get
        {

            return this._ radius;

        }

        set
        {

            this._radius = value;

        }

    }

    …

}

所以,只需寫很少的代碼就能實現簡單屬性。以後如果添加了額外的邏輯,也不會干擾現有的任何應用程序。

 

參考書籍:《Visual C#從入門到精通》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章