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

来源:https://www.cnblogs.com/misakacirno/archive/2020/06/25/13191553.html
-Advertisement-
Play Games

最近在寫一個小工具,裡面用到了一個自定義的類,並且需要對該類進行多個實例化。 因為需要根據需求來取不同的實例,所以決定將其放置到一個字典中,以便取用。 另外,由於可能之後會改動實例化時的內容,所以準備將具體實例化的代碼封裝到一個單獨的子程式中,以便更改。 所以寫瞭如下的代碼: 1 namespace ...


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

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

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

 

所以寫瞭如下的代碼:

 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實際也訪問的是同樣的地址,所以字典內的內容也會隨之改變。

 

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

 

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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Celery 核心模塊 1. Brokers brokers 中文意思為中間人,在這裡就是指任務隊列本身,接收生產者發來的消息即Task,將任務存入隊列。任務的消費者是Worker,Brokers 就是生產者和消費者存放/拿取產品的地方(隊列)。Celery 扮演生產者和消費者的角色。 常見的 ...
  • 1.包裝類是什麼? java中我們經常將基本數據類型轉換為對象,例:將基本數據類型存儲到object[]數組或集合中進行操作 為瞭解決這個問題,Java在設計類的時候為每個基本數據類型設計了一個對應的類進行代表 這八個和基本數據類型對應的類統稱包裝類 包裝類位於java.lang包下 以下是八種數據 ...
  • 一、下載tomcat源碼 https://github.com/apache/tomcat/tree/8.5.x 二、建立pom 1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/PO ...
  • 使用TimerTask創建定時任務,打包之後應用於linux系統 step1:創建java項目 step2:代碼實現 定時任務實現類CreateTask.java是列印操作者的名字 配置準換類Configuration.java 調用ParseConfig的方法convertExecutor()讀取 ...
  • HTTP–Response詳解 博客說明 文章所涉及的資料來自互聯網整理和個人總結,意在於個人學習和經驗彙總,如有什麼地方侵權,請聯繫本人刪除,謝謝! 響應消息數據格式 響應行 組成:協議/版本 響應狀態碼 狀態碼描述 響應狀態碼:伺服器告訴客戶端瀏覽器本次請求和響應的一個狀態 態碼都是3位數字 分 ...
  • 由於在ubuntu環境下,將python做與python3.6做了軟鏈接(ln -s python python3.6),並且pip也被我做了軟鏈接,所以導致用pip安裝virtualenvwrapper之後,在source啟動virtualenvwrapper.sh時以及workon 虛擬環境時總 ...
  • 發文前,說下寫這個的緣故。本來以為自己對java內部類瞭解,其實是我太過於不覺得、以為不重要!所以,今天在重新寫下Demo,為自己記錄一下、回顧一下。 開始~~~ 重新理解什麼是內部類以及寫法、定義等; 代碼一: 1 package com.yk.nbn; 2 /** 3 * @author yk ...
  • 完整逆波蘭計算器(Java) 博客說明 文章所涉及的資料來自互聯網整理和個人總結,意在於個人學習和經驗彙總,如有什麼地方侵權,請聯繫本人刪除,謝謝! 功能 支持 + - * / ( ) 多位數,支持小數, 相容處理, 過濾任何空白字元,包括空格、製表符、換頁符 基本思路 中綴表達式轉尾碼表達式 代碼 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...