• 【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实际也访问的是同样的地址,所以字典内的内容也会随之改变。

    这样说起来可能有点乱,用图来表示应该会明了一些。

    以上均为本人理解,如有疏漏还请各位多多指教。

  • 相关阅读:
    tomcat部署web服务,验证码刷新不出来
    deployment模板实例
    acme
    私有registry及证书配置
    kubernetes监控
    kubernetes中安装efk
    kubernetes v1.13.1集群
    etcd集群
    centos-src
    比较两三个字段的最大值
  • 原文地址:https://www.cnblogs.com/misakacirno/p/13191553.html
Copyright © 2020-2023  润新知