對于C#中b=a的N種情況分析

作者: 包建強  來源: 博客園  發布時間: 2009-10-22 14:22  閱讀: 1305 次  推薦: 0   原文鏈接   [收藏]  

  本文旨在驗證一個容易混淆的概念,從而為《玩轉WPF/Silverlight中INotifyPropertyChanged和ObservableCollection》做鋪墊。

  兩個相同類型的變量a和b,并且有如下關系: 

      b = a;

  如果a發生改變,b是否也發生改變呢?

   情況很復雜,分以下幾種情況談論:

      1) 單個實體

            1. 簡單類型

            先考察int:

            int a = 1;
            
int b = a;

            a 
= 2;
            Console.WriteLine(
"b: " + b);

            輸出結果:

            clip_image002

            再考察一下string:

            string a = "1";
            
string b = a;

            a 
= "2";
            Console.WriteLine(
"b: " + b);

            輸出結果:

            clip_image002[1]

            如果不放心,還可以測試一下Enum,結果類似,詳見Demo。

            結論:簡單類型是組成復合類型的最基本單位,是原子,不可再拆分,所以不管是值類型double、int還是引用類型string,b都不隨a的改變而改變,因為它們指向全局堆棧(對于string而言是托管堆)上的同一個地址。

            2. 復合類型

            復合類型是由string、int、double這些簡單類型組成的。

            分別定義一個復合的引用類型(class)和一個復合的值類型(struct)。 

        class UserInfo
        {
            
public string UserName;
            
public int Age;
        }

        
struct UserInfo2
        {
            
public string UserName;
            
public int Age;
        }


            先討論引用類型: 

            UserInfo a = new UserInfo() { UserName = "Baobao", Age = 27 };
            UserInfo b 
= a;

            a.UserName 
= "AndersLiu";
            a.Age 
= 30;

            Console.WriteLine(
"b.UserName: " + b.UserName);
            Console.WriteLine(
"b.Age: " + b.Age);

            輸出結果:

            clip_image004

            結論:b和a仍然指向托管堆上的同一個UserInfo實例的地址。而UserInfo實例的成員又包含著UserName和Age分別在托管堆和全局堆棧上的地址。所以修改a的成員UserName和Age,只是改變這兩個成員的地址,而沒有改變UserInfo實例的地址,所以b的成員UserName和Age也會跟著改變。

            讓我們局部修改上面的代碼:

            UserInfo a = new UserInfo() { UserName = "Baobao", Age = 27 };

            UserInfo b 
= a;

            
//a.UserName = "AndersLiu";
            
//a.Age = 30;

            a = new UserInfo() { UserName = "AndersLiu", Age = 30 };

            Console.WriteLine(
"b.UserName: " + b.UserName);
            Console.WriteLine(
"b.Age: " + b.Age);

            輸出結果:

            clip_image006

            結論:對a重新進行實例化,導致a指向一個新的UserInfo實例的地址。而b仍然指向原先那個UserInfo實例的地址,所以b不會隨著a的改變而改變。從此b和a是兩個沒有任何關系的變量。

            再來看一下值類型: 

            UserInfo2 a = new UserInfo2() { UserName = "Baobao", Age = 27 };

            UserInfo2 b 
= a;

            a.UserName 
= "AndersLiu";
            a.Age 
= 30;

            Console.WriteLine(
"b.UserName: " + b.UserName);
            Console.WriteLine(
"b.Age: " + b.Age);

            輸出結果:

            clip_image008

            結論:問題集中在b=a這句話上。這時b指向的是a的一份copy,指向全局堆棧上的與a不同的地址。所以b和a是沒有任何關系的,b不隨a的改變而改變。


      2) 集合

            1.集合中一筆數據的增刪修改。

            List<UserInfo> a = new List<UserInfo>();

            List
<UserInfo> b = a;

            a.Add(
new UserInfo() { UserName = "Baobao", Age = 27 });

            Console.WriteLine(
"b.Count after adding: " + b.Count);
            Console.WriteLine();
            Console.WriteLine(
"After modifying a[0]");

            a[
0].UserName = "AndersLiu";
            a[
0].Age = 30;

            Console.WriteLine(
"b[0].UserName: " + b[0].UserName);
            Console.WriteLine(
"b[0].Age: " + b[0].Age);
            Console.WriteLine();

            a.Remove(a[
0]);

            Console.WriteLine(
"b.Count after deleting: " + b.Count);

            輸出結果:

            clip_image010

            結論:b隨著a中數據增減修改而變化。因為b和a指向托管堆上同一個List實例的內存地址,這和復合類型是一樣的。

      數組就不說了,可以看作是多個變量的集合,所以按照集合來處理。寫了幾段測試代碼,放在Demo中。

      示例代碼下載:TestEqual.zip

0
0
 
標簽:ASP.NET C#
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()