Effective C# Item23:避免返回内部类对象的引用
??? 當(dāng)我們將屬性置為只讀后,就可以認(rèn)為調(diào)用者對該屬性的值不可以進(jìn)行更改了嗎?答案是否定的。對于值類型來說,將其置為只讀,確實(shí)可以讓調(diào)用者不能夠?qū)ζ溥M(jìn)行修改;但是對于引用類型來說,調(diào)用者還是可以調(diào)用引用對象的公有成員,包括那些可以修改屬性狀態(tài)的成員。
??? 我們來看下面的代碼。
代碼 1 public struct Employee
2 {
3 private string m_strName;
4 public string Name
5 {
6 get { return m_strName; }
7 set { m_strName = value; }
8 }
9
10 private int m_nAge;
11 public int Age
12 {
13 get { return m_nAge; }
14 set { m_nAge = value; }
15 }
16
17 public Employee(string name, int age)
18 {
19 m_strName = name;
20 m_nAge = age;
21 }
22
23 public override string ToString()
24 {
25 return string.Format("Name : {0}, Age : {1}.", m_strName, m_nAge);
26 }
27 } ??? 下面是測試代碼。
代碼 1 private static void Test()
2 {
3 Employee emp = new Employee("Wing", 24);
4 Console.WriteLine(emp.ToString());
5 ChangeName(emp.Name);
6 ChangeAge(emp.Age);
7 Console.WriteLine(emp.ToString());
8 ChangeEmp(emp);
9 Console.WriteLine(emp.ToString());
10
11 }
12
13 private static int ChangeAge(int age)
14 {
15 age += 1;
16 return age;
17 }
18
19 private static string ChangeName(string name)
20 {
21 name = "UnKnown";
22 return name;
23 }
24
25 private static void ChangeEmp(Employee emp)
26 {
27 emp.Name = "Unkown";
28 emp.Age += 1;
29 } ??? 下面是執(zhí)行結(jié)果。
??? 如果將上面代碼中Employee的類型由struct變?yōu)閏lass,其他代碼不變,執(zhí)行結(jié)果如下。
??? 通過上述代碼,我們可以看到,對于值類型來說,在方法傳遞的過程中,是將對應(yīng)的值進(jìn)行復(fù)制后傳遞的;但是對于引用類型來說,是直接傳遞的引用對象的值。因此,通過調(diào)用方法對值類型的改變并不會對原有值類型的值,但是對于引用類型來說,就直接改變了原有引用對象的值。
??? 我們可以通過以下四種方式來防止類型內(nèi)部的數(shù)據(jù)結(jié)構(gòu)遭到無意的改變:
??? 上述四種方式中,前三種方式都已經(jīng)在示例代碼中進(jìn)行說明了,我們主要看第四種方式,來看下面的代碼。
代碼 1 public class MyBusinessObject
2 {
3 // Read Only property providing access to a
4 // private data member:
5 ? private DataSet _ds;
6 public IList this[ string tableName ]
7 {
8 get
9 {
10 DataView view =
11 _ds.DefaultViewManager.CreateDataView
12 ( _ds.Tables[ tableName ] );
13 view.AllowNew = false;
14 view.AllowDelete = false;
15 view.AllowEdit = false;
16 return view;
17 }
18 }
19 }
20
21
22 // Access the dataset:
23 IList dv = bizOjb[ "customers" ];
24 foreach ( DataRowView r in dv )
25 Console.WriteLine( r[ "name" ] ); ??? 上述代碼中,結(jié)合了第三種方式和第四種方式,首先屬性的返回值由DateView變成了IList,這樣調(diào)用方只能夠調(diào)用IList類型中定義的成員;其次,我們在返回IList之前,將DataView的AllowNew、AllowDelete和AllowEdit屬性都設(shè)置為false,這樣也能夠阻止調(diào)用方對其進(jìn)行改動。
?
??? 總結(jié):將引用類型通過公共接口暴露給外界,將使得類型的用戶不用通過我們定義的方法和屬性,就能夠更改對象的內(nèi)部結(jié)構(gòu),這違反了我們通常的直覺,會導(dǎo)致常見的錯誤。如果我們到處的是引用而非值,那就需要改變類型的接口,如果只是簡單的返回內(nèi)部數(shù)據(jù),那么我們實(shí)際上就給外界賦予了訪問內(nèi)部成員的權(quán)限。客戶代碼可以調(diào)用成員中任何可用的方法。通過使用接口或者包裝器對象向外界提供內(nèi)部的私有數(shù)據(jù),我們可以限制外界對它們的訪問能力。當(dāng)希望客戶代碼更改內(nèi)部數(shù)據(jù)元素時,我們應(yīng)該實(shí)現(xiàn)Observer模式,以使對象可以對更改進(jìn)行校驗(yàn)或響應(yīng)。
轉(zhuǎn)載于:https://www.cnblogs.com/wing011203/archive/2010/01/17/1649819.html
總結(jié)
以上是生活随笔為你收集整理的Effective C# Item23:避免返回内部类对象的引用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 汇编语言学习笔记-按指定的字体输出文本
- 下一篇: C#测试数据库连接是否成功