關於“屬性”的幾個問題,也許面試會問到哦~

一線碼農發表於2014-08-17

 

       這些天太忙了都沒更新部落格了,這篇我們繼續聊聊“屬性”,大家都知道,屬性其實分兩種,無參屬性和有參屬性,顧名思義

無參屬性就是我們平時用到的 “屬性”,有參屬性就是我們所說的 “索引器”,

1     public class Bird
2     {
3         public int Age { get; set; }
4 
5         public string this[int i] { get { return i + string.Empty; } set { ;} }
6     }

乍一看這兩個還是蠻像的,本質上來說這兩個都是getXXX,setXXX方法,只是編譯器為了提高我們的開發效率而做的語法糖。

好,下面回答幾個小問題,當然是我自己的個人見解。

 

Q:為什麼型別中要存在屬性?

A: 一般來說,一個類中都存在一個描述類的狀態資料,我們也可以認為是後設資料,這些後設資料是不可以被輕易修改的,一但

      被錯誤的修改,就會導致類的破壞,所以建議在欄位中加一層殼,由屬性來提供高層訪問。

   舉個例子:Person的Age欄位不能設為<0 || >150的非法資料,這個時候我們就可以在屬性的set方法上進行過濾了。

 1         private int age;
 2 
 3         public int Age
 4         {
 5             get
 6             {
 7                 return age;
 8             }
 9             set
10             {
11                 if (value < 0 || value > 150)
12                     throw new Exception();
13                 age = value;
14             }
15         }

 

Q:  我看到上面欄位age和屬性Age,那麼請問自動屬性有封裝欄位嗎,比如下面的程式碼?

1         public int Age
2         {
3             get;
4             set;
5         }

 

A:其實這個問題問的好,如果你是平時用用而沒有用IL看一下的話,可能還真被蒙到了,既然說到了IL,那就用IL看一下。

從IL上可以清楚的看到其實編譯器給我們生成了一個私有的k__BackingField 欄位。

 

Q: 提到屬性,我想問一下“型別初始化器”和“建構函式”有什麼區別。

1             var b = new Bird { Name = "youyou", Age = 20 };

 

A: 要看有沒有區別,我們得要看到底這個“型別初始化器”到底幹了些什麼?老規矩,我們看看IL程式碼。

從IL上可以看出,兩個nop之間,我們呼叫了建構函式(ctor),並且先後呼叫了set_Name,set_Age方法,所以本質上來說,

“型別初始化器”只是一個語法糖,跟我們手工在建構函式中初始化一樣。

 

Q:我經常看到Session["xxx"],Cookie["xxx"],請問索引器只能用到類的例項上嗎?可不可以

     用到型別上?

A:這個問題問的好,其實你可以發現,我們在定義一個索引器的時候,根本就沒有定義索引器的名字,而是直接用this,重點

    就在這裡,我們知道this表示當前例項的上下文,導致我們的[]只能用到型別的例項上,也就做不了將[]用到型別上。

1         public string this[int i]
2         {
3             get { return i + string.Empty; }
4             set { ;}
5         }

 

Q:從上圖中看到索引器本質上是get_Item,set_Item,但是我如果自己手工定義了一個

   get_Item造成方法名衝突了,這個怎麼辦?

 1     public class Bird
 2     {
 3         public string this[int i]
 4         {
 5             get { return i + string.Empty; }
 6             set { ;}
 7         }
 8 
 9         //重名了,這個怎麼辦?
10         public string get_Item(int s)
11         {
12             return string.Empty;
13         }
14     }

 

A: 這個問題也是蠻有意思的,最常見的做法就是手工修改我們自己定義的方法名,但是我們這裡可不可以另闢蹊徑呢?我們在寫

      WCF的時候,可能會遇到給方法標記別名的情況,然後我們就用OperationContract給方法換一個名字,現在估計就有人想到

     了我是不是也可以給“索引器”加上別名?確實可以這樣,在這裡我們可以用IndexerName來完成。

1         [IndexerName("Fly")]
2         public string this[int i]
3         {
4             get { return i + string.Empty; }
5             set { ;}
6         }

 

然後我們再看看IL程式碼,就這樣成功的修改了索引器的方法名。

 

相關文章