c# 字符串类型在 Object.MemberWiseClone() 中表现为值类型
c# string type behaves as value type in Object.MemberWiseClone()
按照 documentation 的解释和示例(代码很长但很容易理解,直接从文档中复制粘贴)我发现了以下内容:
using System;
public class IdInfo
{
public int IdNumber;
public IdInfo(int IdNumber)
{
this.IdNumber = IdNumber;
}
}
public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo;
public Person ShallowCopy()
{
return (Person) this.MemberwiseClone();
}
public Person DeepCopy()
{
Person other = (Person) this.MemberwiseClone();
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
return other;
}
}
public class Example
{
public static void Main()
{
// Create an instance of Person and assign values to its fields.
Person p1 = new Person();
p1.Age = 42;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(6565);
// Perform a shallow copy of p1 and assign it to p2.
Person p2 = p1.ShallowCopy();
// Display values of p1, p2
Console.WriteLine("Original values of p1 and p2:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Change the value of p1 properties and display the values of p1 and p2.
p1.Age = 32;
p1.Name = "Frank";
p1.IdInfo.IdNumber = 7878;
Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Make a deep copy of p1 and assign it to p3.
Person p3 = p1.DeepCopy();
// Change the members of the p1 class to new values to show the deep copy.
p1.Name = "George";
p1.Age = 39;
p1.IdInfo.IdNumber = 8641;
Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p3 instance values:");
DisplayValues(p3);
}
public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}", p.Name, p.Age);
Console.WriteLine(" Value: {0:d}", p.IdInfo.IdNumber);
}
}
在第二个输出中,我预计 p2.Name
是 Frank,因为 string
是根据 documentation 的引用类型,因此应该受到原始名称更改的影响对象。
// The example displays the following output:
// Original values of p1 and p2:
// p1 instance values:
// Name: Sam, Age: 42
// Value: 6565
// p2 instance values:
// Name: Sam, Age: 42
// Value: 6565
//
// Values of p1 and p2 after changes to p1:
// p1 instance values:
// Name: Frank, Age: 32
// Value: 7878
// p2 instance values:
// Name: Sam, Age: 42 ---> EXPECTED FRANK HERE
// Value: 7878
//
// Values of p1 and p3 after changes to p1:
// p1 instance values:
// Name: George, Age: 39
// Value: 8641
// p3 instance values:
// Name: Frank, Age: 32
// Value: 7878
其实这两个字段在DeepCopy方法中都有处理:
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
为什么 IdInfo.Value
会受到原始对象变化的影响,而 Name
如果两者都是引用类型则不会?
这里没有任何内容取决于字符串是引用类型还是值类型。您创建了 Person
的克隆 - 此时,p1
和 p2
都将 .Name
指向同一个 string
对象。然后,您更改 p1
上的 .Name
。重要的是:*这根本不会影响字符串 - 它只是将 p1
更改为指向一个 完全不同的字符串 。这就是这里发生的一切。
由于字符串表面上是不可变的,因此您几乎总是要更改值以指向完全不同的字符串;您(几乎)实际上从未 更改 存在的字符串,因此:无论是引用类型还是值类型都很少相关,除非在理解内存使用方面。
出于同样的原因:确实没有必要调用 string.Copy
,并且 string.Copy
可以 实现为 return value;
(它不是,虽然 - 我检查过)
按照 documentation 的解释和示例(代码很长但很容易理解,直接从文档中复制粘贴)我发现了以下内容:
using System;
public class IdInfo
{
public int IdNumber;
public IdInfo(int IdNumber)
{
this.IdNumber = IdNumber;
}
}
public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo;
public Person ShallowCopy()
{
return (Person) this.MemberwiseClone();
}
public Person DeepCopy()
{
Person other = (Person) this.MemberwiseClone();
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
return other;
}
}
public class Example
{
public static void Main()
{
// Create an instance of Person and assign values to its fields.
Person p1 = new Person();
p1.Age = 42;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(6565);
// Perform a shallow copy of p1 and assign it to p2.
Person p2 = p1.ShallowCopy();
// Display values of p1, p2
Console.WriteLine("Original values of p1 and p2:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Change the value of p1 properties and display the values of p1 and p2.
p1.Age = 32;
p1.Name = "Frank";
p1.IdInfo.IdNumber = 7878;
Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Make a deep copy of p1 and assign it to p3.
Person p3 = p1.DeepCopy();
// Change the members of the p1 class to new values to show the deep copy.
p1.Name = "George";
p1.Age = 39;
p1.IdInfo.IdNumber = 8641;
Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p3 instance values:");
DisplayValues(p3);
}
public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}", p.Name, p.Age);
Console.WriteLine(" Value: {0:d}", p.IdInfo.IdNumber);
}
}
在第二个输出中,我预计 p2.Name
是 Frank,因为 string
是根据 documentation 的引用类型,因此应该受到原始名称更改的影响对象。
// The example displays the following output:
// Original values of p1 and p2:
// p1 instance values:
// Name: Sam, Age: 42
// Value: 6565
// p2 instance values:
// Name: Sam, Age: 42
// Value: 6565
//
// Values of p1 and p2 after changes to p1:
// p1 instance values:
// Name: Frank, Age: 32
// Value: 7878
// p2 instance values:
// Name: Sam, Age: 42 ---> EXPECTED FRANK HERE
// Value: 7878
//
// Values of p1 and p3 after changes to p1:
// p1 instance values:
// Name: George, Age: 39
// Value: 8641
// p3 instance values:
// Name: Frank, Age: 32
// Value: 7878
其实这两个字段在DeepCopy方法中都有处理:
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
为什么 IdInfo.Value
会受到原始对象变化的影响,而 Name
如果两者都是引用类型则不会?
这里没有任何内容取决于字符串是引用类型还是值类型。您创建了 Person
的克隆 - 此时,p1
和 p2
都将 .Name
指向同一个 string
对象。然后,您更改 p1
上的 .Name
。重要的是:*这根本不会影响字符串 - 它只是将 p1
更改为指向一个 完全不同的字符串 。这就是这里发生的一切。
由于字符串表面上是不可变的,因此您几乎总是要更改值以指向完全不同的字符串;您(几乎)实际上从未 更改 存在的字符串,因此:无论是引用类型还是值类型都很少相关,除非在理解内存使用方面。
出于同样的原因:确实没有必要调用 string.Copy
,并且 string.Copy
可以 实现为 return value;
(它不是,虽然 - 我检查过)