我创建了一个名为Colors的类。我在Colors对象上设置了某些属性并将其设置在Session变量中。当我在另一个页面上访问Session变量时,我注意到如果我在下面的objColors上更改属性,它会更改Session并且不保留原始属性,这是我想要它做的。这是一个例子:
Session["Colors"] = Colors;
Colors objColors = Session["Colors"];
//If I change objColors, it changes the Session. I don't want this to happen.
有没有更好的方法来保留原始属性?为什么这样做?
答案 0 :(得分:7)
为Colors创建一个复制构造函数。然后,这样做。
Colors objColors = new Colors((Colors)Session["Colors"]);
在新的构造函数中,只需复制所需的值并执行与构造函数相关的其他操作。
您的代码中发生的事情是您正在向Colors对象获取 指针 。 Session [“Colors”]和objColors指向内存中的同一个对象,因此当您修改一个对象时,更改会反映在两者中。你想要一个品牌spankin'新的Colors对象,其值从objColors或Session [“Colors”]初始化。
编辑:复制构造函数可能如下所示:
public Colors(Colors otherColors)
{
this.privateVar1 = otherColors.privateVar1;
this.publicVar2 = otherColors.publicVar2;
this.Init();
}
答案 1 :(得分:3)
您可以实现自己的克隆方法来制作对象的“副本”。之所以发生这种情况,是因为Colors objColors = Session["Colors"];
的赋值是一个引用赋值,这是设计的。您所做的只是对已存在的对象进行局部范围引用。查看IClonable进行实际对象克隆。您无需实现自己的复制方法。您可能还需要查看MemberwiseClone,具体取决于对象的深度。
答案 2 :(得分:3)
尝试复制构造函数。
示例:link
答案 3 :(得分:2)
通过引用而不是按值访问对象。 See here。有几种方法可以改变这种情况。查看网站了解详细信息。
答案 4 :(得分:2)
其他答案都建议以某种方式进行克隆。可能适合您的特定情况的替代方法是使您的类型不可变。之前改变您的类型的操作现在将返回该类型的新实例,从原始对象获取数据并进行适当的更改,并使原始实例保持原样。例如,这是String
类所采用的方法。
当然,您仍然必须编写适当的代码来复制实例中的数据 - 但使用该类型的代码最终可能会更简单。
这可能不适合你的情况,但这是一种至少要考虑的技术。
答案 5 :(得分:1)
默认情况下没有内置和实现的方法,但您可以通过实现ICloneable并调用MemberwiseClone来实现。这只适用于浅拷贝 - 如果你的对象包含其他对象,你也需要克隆它们。一个简单的实现是:
public class Bla : ICloneable
{
string _someFieldToClone;
object ICloneable.Clone()
{
return this.Clone();
}
public Bla Clone()
{
return (Bla)MemberwiseClone();
}
}
答案 6 :(得分:1)
这样做是因为您实际上并未复制对象,而是复制对象的引用。您可以使用二进制序列化轻松地在C#中进行深层复制:
public static MemoryStream Serialize(object data)
{
MemoryStream streamMemory = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
formatter.Serialize(streamMemory, data);
return streamMemory;
}
public static Object Deserialize(MemoryStream stream)
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
return formatter.Deserialize(stream);
}
您可以调用这两个方法,首先获取一个对象并将其数据写入MemoryStream。然后,您可以调用Deserialize以根据该数据获取对象的新副本。
您的对象最后需要使用Serializable,方法是在每个对象上放置Serializable属性。
答案 7 :(得分:0)
这是因为objColors和Session [“Colors”]对象是同一个对象。如果您想存储副本并保留原件,则需要使对象可以克隆。
请参阅以下SO Q& A,了解正确方向的指针:
答案 8 :(得分:0)
由于类Color是你创建的,我认为你是面向对象编程的新手,你可以像Stuart一样创建一个类似于以下内容的副本constructor:
public class Colors
{
public int Property1;
public int Property2;
public int Property3;
public Colors()
{
//Do your regular constructor here
}
public Colors(Colors colorToCopy)
{
this.Property1 = colorToCopy.Property1;
this.Property2 = colorToCopy.Property2;
this.Property3 = colorToCopy.Property3;
}
}
通过序列化克隆是一个更通用的解决方案,并确保深度复制(意味着它将复制使属性副本以及属性的属性)但是有点难以理解imo。使用此解决方案,如果属性不是原始数据类型,那么除非您明确地将它们复制,否则它们不会是副本。
答案 9 :(得分:0)
当你有一个变量并为其分配会话值时,你会得到一个指向它们的指针。
Colors objColors = (Colors)Session["Colors"];
Session [“Colors”]和objColors指向内存中的同一个对象,然后当你在一个对象中进行更改时,更改会反映在两者中。
如果您想要独立,需要获得对象的 Deep Copy 。您必须为Invoice及其所有相关类实现IClonable接口:
public class Colors: IClonable
{
public int Red;
public int Green;
public int Blue;
public object Clone()
{
return this.MemberwiseClone();
}
}
现在您拥有发票对象的真实深层副本。
Colors objColors = (Colors)((Colors)Session["Colors"]).Clone();
更多信息:使用IClonable和MemberwiseClone进行对象克隆,具体取决于对象的深度。