using System;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
ObjectA objectA = new ObjectA();
objectA.Id = 99;
objectA.Name = "Joe King";
Console.WriteLine("BEFORE");
Console.WriteLine(objectA.Id.ToString() + "|" + objectA.Name);
ObjectB objectB = new ObjectB(objectA);
objectB.DoSomething();
Console.WriteLine("AFTER");
Console.WriteLine(objectA.Id.ToString() + "|" + objectA.Name);
}
}
public class ObjectB
{
ObjectA _objA = null;
ObjectA _objACopy = null;
public ObjectB(ObjectA objA)
{
_objA = objA;
_objACopy = Object.Clone<ObjectA>(objA);
}
public void DoSomething()
{
_objA.Id = 100;
_objA.Name = "Bob Smith";
}
}
public class ObjectA
{
public int Id {get;set;}
public string Name {get;set;}
}
public class Object
{
public static T Clone<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
}
这给出了我的以下结果,这是正确的。
在
99 | Joe King
在
100 | Bob Smith
但是,如果我想撤消对原始对象的更改,我将方法DoSomething()更改为this(这是Fiddle)
public void DoSomething()
{
_objA.Id = 100;
_objA.Name = "Bob Smith";
_objA = _objACopy;
}
但结果是错误的;
之前
99 | Joe King
AFTER
100 | Bob Smith
正确的结果应如下所示;
之前
99 | Joe King
AFTER
99 | Joe King
因此,通过将Object分配给Object不起作用,但如果我像这样分配每个单独的属性,它确实有效(这是Fiddle)
public void DoSomething()
{
_objA.Id = 100;
_objA.Name = "Bob Smith";
_objA.Id = _objACopy.Id;
_objA.Name = _objACopy.Name;
}
有人可以帮我理解出了什么问题以及为什么我可以打电话
_objA = _objACopy;
返回原始对象。
答案 0 :(得分:2)
问题在于,C#中的对象变量是引用类型。
引用类型变量是变量,仅包含对象存储在内存中的位置的引用。如果现在将一个对象分配给另一个对象,它只会将该内存地址分配给您的变量。
所以你现在有两个变量objA
和objACopy
,它们都指向你记忆中的同一个对象。如果您现在更改了Id
的属性objA
,那么objACopy
也会更改。{/ p>
objACopy = objA;
objACopy.Id = 1111;
// objA.Id is now also changed to 1111, beacuse they point to the same memory address
如果您想更改objA
,而不影响objACopy
,则必须复制整个对象而不是仅复制内存地址。为此,您可以使用new
关键字创建一个新对象,并将其属性从另一个对象复制。这样你最终得到了两个不同的对象,每个对象都有自己的内存空间,并且不会相互影响。
答案 1 :(得分:0)
由于_objA = _objACopy
并未更改最初分配给_obja
的对象,因此它只会更改_objA
引用的对象。
这是重现问题的最小例子:
public class Foo
{
public string Bar { get; set; }
}
public class Program
{
public static void Main()
{
var foo = new Foo { Bar = "bar" };
Console.WriteLine("Before: {0}", foo.Bar);
ChangeBar(foo);
Console.WriteLine("After: {0}", foo.Bar);
ChangeBarReference(foo);
Console.WriteLine("After reference: {0}", foo.Bar);
}
private static void ChangeBar(Foo foo)
{
foo.Bar = "baz";
}
private static void ChangeBarReference(Foo foo)
{
foo = new Foo { Bar = "qux" };
}
}
打印:
Before: bar
After: baz
After reference: baz
而不是&#34; qux&#34;在最后一行,因为只有在签名ref Foo foo
时才能这样做。
private static void ChangeBarReferenceRef(ref Foo foo)
{
foo = new Foo { Bar = "tok" };
}
// ...
ChangeBarReferenceRef(ref foo);
Console.WriteLine("After ref reference: {0}", foo.Bar);
打印:
Before: bar
After: baz
After reference: baz
After ref reference: tok