c#值类型和引用类型

时间:2017-08-27 12:04:53

标签: c#

我开始学习C#并且可以使用以下结果向我解释有关值类型和引用类型的信息。我的理解是整数和结构是值类型因此因此被复制到赋值中,字符串和类是引用类型,因此只复制引用而不是底层对象。这是我测试它的代码:

struct MyStruct
    {
        public class C
        {
              public string _string;
        };

        public C _c;
        public string _string;
        public int _a;

        public MyStruct(int a, string s) 
        {
            _a = a; 
            _c = new C();
            _c._string = s;
            _string = s;
        }
    };
    public static void Main(string[] args)
    {
        MyStruct stru = new MyStruct(4, "Hello");
        MyStruct stru2 = stru;
        stru2._a = 5;
        stru2._string = "World";
        stru2._c._string = "World";
        Console.WriteLine("Stru _a: " + stru._a);
        Console.WriteLine("Stru2 _a: " + stru2._a);
        Console.WriteLine("Stru _string: " + stru._string);
        Console.WriteLine("Stru2 _string: " + stru2._string);
        Console.WriteLine("Stru C _string: " + stru._c._string);
        Console.WriteLine("Stru2 C _string: " + stru2._c._string);
    }

在这个人为的例子中,我得到以下输出:

Stru _a: 4
Stru2 _a: 5
Stru _string: Hello
Stru2 _string: World
Stru C _string: World
Stru2 C _string: World

int变量_a非常有意义。它是一个值类型,因此它被复制而不被引用,因此对“Stru2”的更改不会影响“Stru”。 _string让我感到惊讶,因为它是一个引用类型,我希望这两个值都输出为“World”。我希望_c._string都像它一样是“世界”,但是我不明白为什么行为与_string不同而不是类的一部分。 任何解释将不胜感激。 谢谢!

4 个答案:

答案 0 :(得分:1)

  

我的理解是整数和结构是值类型因此因此被复制到赋值中,字符串和类是引用类型,因此只复制引用而不是底层对象。

这是正确的。但是,通过相同的逻辑,当您复制包含引用类型成员的结构时,将复制其引用值,而不是基础值。因此,当您复制结构时,其所有值都将复制到复制的结构:int ,字符串引用C < em> reference ,因为C是引用类型。

因此,两个struct副本都包含对同一底层C对象的引用。因此,如果您改变C对象,则更改将出现在两个结构中,因为它们都引用同一个对象。

但是对于_string成员,当您执行stru2._string = "World"时,替换引用。这会更改stru2结构,但因为它是stru的完整副本,所以原始结构不会受到影响。

仅仅因为一种类型是值类型(或引用类型),并不意味着其成员也具有相同的效果。

答案 1 :(得分:1)

    struct MyStruct // Value type
    {
        public class MyClass // Ref type
        {
            public string myClassString;
        };

        public MyStruct(int a, string s)
        {
            myStrucInt = a;
            myClass = new MyClass();
            myClass.myClassString = s;
            myStractString = s;
        }

        public MyClass myClass;
        public string myStractString;
        public int myStrucInt;

    };
    public static void Main(string[] args)
    {
        MyStruct stru = new MyStruct(4, "Hello"); // val type
        MyStruct stru2 = stru; // val type (makes a copy for stru)

        stru2.myStrucInt = 5;
        stru2.myStractString = "World";
        stru2.myClass.myClassString = "World";

        Console.WriteLine("Stru _a: " + stru.myStrucInt); // 4
        Console.WriteLine("Stru2 _a: " + stru2.myStrucInt); // 5
        Console.WriteLine("Stru _string: " + stru.myStractString); // Hello is original value of stru (struct is value type)
        Console.WriteLine("Stru2 _string: " + stru2.myStractString); // World
        Console.WriteLine("Stru C _string: " + stru.myClass.myClassString); // World
        Console.WriteLine("Stru2 C _string: " + stru2.myClass.myClassString); // World
    }

答案 2 :(得分:0)

那是因为两个结构共享同一个MyStruct.C类的实例。你可以像这样测试它

Console.WriteLine(stru._c == stru2._c);

当您创建第二个结构并初始化第一个结构时,第一个结构对MyStruct.C实例的引用,第一个结构保留了引用,被复制到第二个结构。

我建议您对代码进行以下更改

//stru2._c._string = "World";
stru2._c = new MyStruct.C();
stru2._c._string = "World";

答案 3 :(得分:0)

我认为这是因为字符串是不可变的 获取相同值的任何字符串变量都指向内存中的同一共享位置。 所以当你设置stru2 = stru,stru._string和stru2._string指向同一个地方时,当你设置stru2._string =“World”时,stru2._string指向一个新的地方而不是stru._string。 对于_c,情况有所不同:由于stru._c和stru2._c指向同一个地方,所以stru2._c的任何属性的任何更改都将改变stru._c的任何属性。