大家來討論下C#無參屬性這個東西到底有沒有存在的必要?
永遠不要公開類型的字段,面向對象設計和編程的重要原則之一就是 數據封裝。如果公開類型的字段,會很容易的寫出不恰當使用字段的代碼。這裡可以把字段聲明為private,然後聲明訪問器方法。
class test
{
private string Name;
public void SetName(string value)
{
Name = value;
}
public string GetName()
{
return Name;
}
}
復制代碼
實現只讀或只寫就是這麼簡單,不實現一個索引器方法就行了。還可以將Setname方法標記為protected,就可以只允許派生類修改了。聰明的你也發現上面這個做法的缺點了吧,首先得去實現額外的方法,所以會產生更多的代碼,其次,如果調用的時候必須調用方法,不能直接引用一個字段名。還好C#給我們提供了一個稱為屬性(property)的機制,它緩解了第一個缺點造成的影響,也消除了第二個缺點。
class test
{
private string name;
public string Name {
get { return name; }
set { if ("狗剩" == value) { Console.WriteLine("系統崩潰,拋出異常"); return; } name = value; }
}
}
復制代碼
屬性可以用任意的可訪問修飾符來標記。不能定義名稱相同的屬性。
如果只是為了封裝一個支持字段而創建屬性,C#還提供一一種更簡單的語法,稱為自動實現的屬性(Automatically Implemented Property,簡稱AIP)。like this
class test
{
public int Age
{
get;
set;
}
}
復制代碼
如果聲明一個屬性而不提供get/set實現,C#會自動為你聲明一個私有字段。原始代碼是這樣的:
public int Age
{
[CompilerGenerated]
get
{
int num;
num = this.<Age>k__BackingField;
Label_0009:
return num;
}
[CompilerGenerated]
set
{
this.<Age>k__BackingField = value;
return;
}
}
復制代碼
和直接聲明一個public 的Age字段相比,自動實現的屬性的優勢在哪?兩者存在一處重要的區別:使用自動實現的屬性(AIP)意味著已經創建一個屬性,訪問該屬性的時候會調用get/set方法。如果有一天你決定自己實現這個AIP的get/set,而不接受編譯器默認的實現,那麼訪問這個屬性的任何代碼都不必重新編譯。如果是一個public的Age字段,如果你把它更改為屬性,那麼訪問這個字段的所有代碼就都需要重新編譯了。
凡事都有好有壞,那麼AIP有哪些不討人喜歡的地方呢:
1.如果使用字段聲明的語法,可以包含初始化的部分,如果使用AIP就不行了,必須在咩個構造器中顯示的初始化每個AIP。
2.AIP支持的字段名是由編譯器決定的,而且每次重新編譯,這個字段名可能會發生更改,這樣一來,只要含有一個AIP就不能對類型的實例進行反序列化了。在任何想要序列化或反序列化的類型中,都不要使用AIP功能。
3.不能在AIP的get/set添加斷點,所以不好檢測程序在什麼時候獲取或設置這個屬性。咱手動實現的就可以設置斷點,不信你試試。
AIP功能是作用於整個屬性的:要麼都用,要麼都不用,這意味這,如果顯式的實現get那麼set也要顯式實現,反之亦然。
屬性看起來與字段相似,但本質上是方法。屬性與字段的區別如下:
1.屬性可以是只讀或只寫的(get/set訪問器方法),字段卻總是可讀可寫的。
2.屬性方法可能拋出異常,字段訪問不會拋出。
3.屬性不能作為out或ref參數傳遞給方法,字段可以。
class Program
{
public int Age
{
get {return 3 ;}
set{}
}
int age;
static void Main()
{
var t = new { name="XiaoBai",age=22 };
test tt = new test();
//tt.Name = "狗剩";
Program p = new Program();
some(out p.age);
some(out p.Age);//屬性,索引器或動態成員不得作為out或ref參數傳遞
Console.ReadKey();
}
static void some(out int age)
{
age = 10;
}
}
www.2cto.com
4.屬性方法可能花費較長時間執行,字段的訪問都是立即完成。
5.屬性方法可能需要額外的內存,或者返回一個不正確的引用,指向不屬於對象狀態一部分的某個東西,這樣一來,對返回對象的修改就作用不到原始對象身上了,相反查詢字段返回的總是正確的引用,它指向的東西保證是原始對象狀態的一部分。使用會返回一個拷貝的屬性時,非常容易引起混淆。
如果仔細研究下屬性和字段的差別,你會發現只有在極個別的情況下屬性才真正有用。屬性唯一的好處就是提供了簡化的語法,和調用普通方法(非屬性中的方法)相比,屬性不僅不會提升代碼的性能,還會妨礙對代碼的理解。
屬性訪問器的可訪問性:
我們有時希望為get訪問器指定一種可訪問性,為set訪問器指定另一種訪問器:
class test
{
public int Age
{
get { return age; }
protected set { if (value < 0) Console.WriteLine("年齡錯誤!"); else { age = value; } }
}
int age;
}
復制代碼
如上所述,Age屬性本身聲明為public,意味這get訪問器方法是公共的,可由所有代碼訪問,但是,注意set訪問器方法被聲明為protected,只能從test的內部定義的代碼中調用,或者從test的派生類的代碼中調用。
定義一個屬性時,如果兩個訪問其方法需要具有不同的可訪問性,C#語法要求必須為屬性本身指定限制最不大的那一種可訪問性,然後在兩個訪問其中,只能選擇一個來應用限制較大的那一種可訪問性。在前面的例子中,屬性本身為public,set訪問器為protected(限制比public大)。
class test
{
private int Age
{
get { return age; }
protected set { if (value < 0) Console.WriteLine("年齡錯誤!"); else { age = value; } }//這裡就通不過編譯
}
int age;
}
摘自 小小白白