以下是我的课程
public Class Test
{
int id {get;set;}
string name {get;set;}
}
我正在创建此类的对象并分配值。
var obj = new Test();
obj.id = 1;
obj.name = "test";
var newobj = obj;
newobj.name ="NewTest";
以下是输出
Console.WriteLine(obj.name); //NewTest
Console.WriteLine(newobj.name); //NewTest
为什么当我改变新obj中存在的属性的值时,obj的值正在改变。我知道它的解决方案,我不知道为什么我找不到。如果我在newobj中更改了值,我不希望obj的值被改变。
答案 0 :(得分:5)
您没有创建副本,只是将对象(obj
)的引用分配给另一个变量(newobj
)。访问其中任何一个都指向内存中的相同位置。
要创建对象的副本,您必须克隆它。见https://stackoverflow.com/a/78612/1028323 https://stackoverflow.com/a/129395/1028323 例如。
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T) formatter.Deserialize(ms);
}
}
答案 1 :(得分:3)
正如评论中所提到的,obj和newObj都指向相同的底层内存对象,这就是为什么在一个内容上进行更改也会改变另一个内容的原因。这是因为它们是引用类型(而不是值类型)。如果你想要两个不同的对象,你有几个选择。第一种是创建一个新对象并手动分配属性:
var test1 = new Test() { id = 1, name = "Foo }
var test2 = new Test() { id = test1.id, name = test1.name }
第二个选项是克隆对象。虽然有很多方法可以做到这一点(反射,序列化,表达式树,第三方库),但我发现使用序列化是执行克隆的最简单方法,前提是您不打算这样做每秒的次数。有关使用BinaryFormatter克隆对象的信息,请参阅下面的答案。
答案 2 :(得分:2)
newobj
未创建新实例...它只是指向您使用var obj = new Test();
创建的同一实例的另一个指针
答案 3 :(得分:0)
var newobj = obj;
这导致obj的引用被分配给newobj。它们指向上述语句的内存位置确实没有区别。 如果你想让obj具有相同的值,但是当newobj的值发生变化时你不会受到影响,你应该这样做。
var obj = new Test();
obj.id = 1;
obj.name = "test";
var newobj = new Test();
newobj.id = obj.id;
newobj.name = obj.name;
newobj.name ="NewTest";
答案 4 :(得分:0)
这个愚蠢的比喻正好在你的代码中发生了什么:
Test
创建的new
实例是您的公寓。obj
是您的一组密钥。newObj
是您提供清洁服务的副本。Name
正在清理您的公寓(以某种方式修改对象)。要清楚明白这一点,重要的是obj
或newObj
的值不是 Test
的实例。存储在变量中的值是对象存在的内存地址。
与密钥相同,您可以访问公寓,变量obj
和newObj
可让您访问他们所指向的对象。将变量obj
复制到newObj
时,您只需复制访问对象(内存地址)的方法,而不是对象本身。
事物与价值类型截然不同,但这是另一个故事。