【C#】關於字典存儲不同類型變量的效果


最近在寫一個小工具,里面用到了一個自定義的類,並且需要對該類進行多個實例化。

因為需要根據需求來取不同的實例,所以決定將其放置到一個字典中,以便取用。

另外,由於可能之后會改動實例化時的內容,所以准備將具體實例化的代碼封裝到一個單獨的子程序中,以便更改。

 

所以寫了如下的代碼:

 1 namespace Example
 2 {
 3     public partial class MainWindow : Window
 4     {
 5         //因為在其他地方會引用到,所以放在最外層定義
 6         public static MyClass staff1; 
 7         public static MyClass staff2;
 8         public static Dictionary<string, MyClass> staffDic = new Dictionary<string, MyClass>()
 9         {
10             {"aaa",staff1},
11             {"bbb",staff2}
12         };
13 
14         private void Window_Loaded(object sender, RoutedEventArgs e)
15         {
16             InitializationStaff();
17             System.Console.WriteLine(staffDic["aaa"]);
18         }
19 
20         private void InitializationStaff() //給變量添加實例
21         {
22             staff1=new MyClass(){a=1,b=2,c=3};
23             staff2=new MyClass(){a=3,b=2,a=1};
24         }
25     }
26 
27     Class MyClass 
28     {
29         public int a;
30         public int b;
31         public int c;
32     }
33 }

結果發現,輸出的時候報錯了,提示在字典中該項對應的內容為Null。

而如果將代碼修改一下,在外面先實例化一下:

namespace Example
{
    public partial class MainWindow : Window
    {
        //因為在其他地方會引用到,所以放在最外層定義
        //在定義變量時就實例化
        public static MyClass staff1 = new MyClass(); 
        public static MyClass staff2 = new MyClass();
        public static Dictionary<string, MyClass> staffDic = new Dictionary<string, MyClass>()
        {
            {"aaa",staff1},
            {"bbb",staff2}
        };

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            InitializationStaff();
            System.Console.WriteLine(staffDic["aaa"]);
        }

        private void InitializationStaff() //給變量修改內容
        {
            staff1.a = 1;
            staff1.b = 2;
            staff1.c = 3;

            staff2.a = 3;
            staff2.b = 2;
            staff2.a = 1;
        }
    }

    Class MyClass 
    {
        public int a;
        public int b;
        public int c;
    }
}

此時,輸出的內容就正常了。

那么究竟這背后發生了什么呢?

 

在請教過朋友后了解到,在C#中,為字典添加key對應的value時,實際上發生的效果是將目標內容復制到字典中,而並非是引用

了解過變量和內存相關知識的人應該知道,當我們寫下一行代碼:

int a = 123;

此時發生的是,系統首先找到一塊內存空間,把123這個值存儲到其中,並記錄該內存空間的地址A。

而在變量a中,實際存儲的內容就是地址A。

 

當我們將變量添加至字典中時:

Dictionary<string, int> Dic = new Dictionary<string, int>() { { "number1", a } };

字典首先找到a這個變量,得到了存儲着數據的地址A。

隨后將地址A中的內容復制,並粘貼到字典開辟出的另一塊內存空間中。而這個內存空間的地址是地址B。

此時,無論我們給變量a如何賦值,字典中的a是不會改變的。

因為在給變量a賦值時,實際修改的是地址為A的內存空間中的數據,而字典中的a存儲在的位置是地址為B的內存空間中。

 

可是,如果按照這個結論來看,在本文開頭部分我用的第二種方法,也應該是在外部修改了類中成員的數據后,字典中的內容不變啊?

那為什么在外部修改的時候字典內的內容也改變了呢?

 

當我們寫下以下代碼的時候:

 1 namespace Example
 2 {
 3     public partial class MainWindow : Window
 4     {
 5         private void Window_Loaded(object sender, RoutedEventArgs e)
 6         {
 7             public static MyClass staff = new MyClass(); 
 8         }
 9     }
10 
11     Class MyClass 
12     {
13         public int a;
14         public int b;
15         public int c;
16     }
17 }

變量staff中,存儲了一個地址A,地址A處存儲了MyClass這樣的一個類型,也就是a、b和c三個變量。

而a、b和c三個變量,實際上是分別存儲了地址a,地址b,地址c。

這三個地址所指向的地方,才是各自存儲了數據的內存空間。

 

當我們將staff添加到字典中時,字典讀取到了地址A,並將地址A處存儲的內容復制到了自己新開辟的、在地址B處的內存空間中。

在復制的時候,a、b、c三個變量的地址也就隨着被復制到了地址B處中。

 

這個時候,外部的變量staff和字典中的staff,都會指向同樣的三塊內存空間。

當通過外部變量staff修改內容時,由於字典內的staff實際也訪問的是同樣的地址,所以字典內的內容也會隨之改變。

 

這樣說起來可能有點亂,用圖來表示應該會明了一些。

 

以上均為本人理解,如有疏漏還請各位多多指教。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM