2017-08-27 99 views
1

我开始学习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而不是类的一部分。 任何解释将不胜感激。 谢谢!

回答

0

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

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

测试当你用第一个的MyStruct.C实例的引用,到第一个结构holded者一个参考初始化它创建第二个结构,得到了复制到第二个结构。

我建议做如下改变了代码

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

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

+0

*“的任意字符串变量,得到了相同的值指向同一共享发生在存储器” * - 虽然这有时是真实的,由于[字符串实习](https://stackoverflow.com/q/ 8054471/216074),这种行为不能保证或不被要求发生(情况往往不会如此)。 'stru._string'和'stru2._string'将指向相同的地方,因为*参考在复制结构时被复制。 – poke

1

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

这是正确的。但是通过相同的逻辑,当您复制包含引用类型成员的结构时,其引用值将被复制,而不是基础值。所以,当你让你的结构的副本,它的所有的值复制到复制的结构:通过int ,串参考C参考因为C是引用类型。

所以这两个结构副本都包含对同一底层对象的引用。所以如果你改变了这个对象,两个结构中都会出现变化,因为它们都指向同一个对象。

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

仅仅因为一种类型是值类型(或参考类型),并不意味着它的成员也处于相同的效果。

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 
    }