-1

我的问题涉及 C# 中对象的使用。我想我明白发生了什么,但我想知道为什么。由于我不会深入讨论的原因,我想用它的当前数据(当前状态)创建一个对象的临时副本。所以我想我可以创建一个新对象,将其分配给原始对象,然后更改原始对象。那时我会有两个处于不同状态的对象。但是发生的情况是,复制的对象最终看起来与第一个完全一样。这里有一些代码来说明:

Order o1 = new Order();
o1.property1 = "test 1";

Order o2 = new Order();
o2 = o1;

o1.property1 = "test 2";

但在这段代码的末尾,o1 和 o2 都将 property1 设置为“test 2”。我想我意识到所有对象都只是指针,所以如果你改变一个,它就会改变另一个,但我不明白为什么会这样,或者为什么它有用。我在这里缺少一些基本的东西吗?另外,完成我想做的事情的最佳方法是什么?即:存储对象的状态,进行更改,然后在必要时恢复。希望这是有道理的。

4

7 回答 7

7

C# 中的对象变量是对内存中特定对象的引用(不是指针)。当你声明

Order o2 = new Order();

您正在堆中创建一个新的 Order 对象,并将对该对象的引用分配给您的 o2 变量。当你然后陈述

o2 = o1;

您是在告诉编译器使 o2 成为对 o1 的引用。此时,对原始 o2 对象的引用丢失,并且该对象的内存将在下一次垃圾收集扫描期间被移除。

此后,o1 和 o2 都引用内存中的同一个对象。要将信息从一个对象复制到另一个对象,您需要实现一个过程来实例化一个新的目标对象并将所有数据从一个对象复制到另一个对象。有关更多信息,请参阅 ICloneable 上的 MSDN 文档。

于 2013-03-05T23:02:04.053 回答
4

您指的是值类型和引用类型之间的区别。显然你的Order对象是一个引用类型,我会假设它是一个类。

类是引用类型,这意味着它们是“指针”。造成这种情况的原因之一是性能,因为您不希望每次分配变量时都复制大量数据。

结构是值类型,在分配它们时会复制到内存中。

您有 2 个解决方案:

  • 使用结构而不是类
  • 如果非常简单,请使用MemberwiseClone克隆您的对象,或者如果您需要执行深度克隆,请使用您自己的方法。
于 2013-03-05T22:59:50.523 回答
2

这是设计使然。如果您想克隆并保持克隆独立,我建议您在您的类型上实现“克隆”机制。这可以是ICloneable甚至只是一个构造函数,它接受一个实例并从中复制值。

于 2013-03-05T22:56:55.050 回答
2

关于你的问题

完成我想做的事情的最佳方法是什么?即:存储对象的状态,进行更改,然后在必要时恢复

一个简单的方法是简单地序列化对象,例如使用XMLSerializer. 然后,如果您想丢弃更改,只需反序列化原始对象并将修改后的对象替换为原始版本即可。

于 2013-03-05T23:07:45.320 回答
2

使用结构来完成任务,类是引用类型,结构是值类型。类存储在内存堆上,结构存储在堆栈上。有关更多信息,请搜索 Structs vs Classes 并了解差异

于 2013-03-05T23:23:15.127 回答
1

根据定义,对象是一个“指针”;它们包含对您的数据的引用,而不是实际数据本身。您可以为它分配一个值类型,它会给出保存数据的外观。

如上所述,了解值类型与引用类型是关键。

于 2013-03-05T22:57:36.523 回答
1

除了对象引用,Java 没有任何非原始数据类型的概念;因为几乎可以对对象引用所做的任何事情都涉及对所引用的对象.(Java 中的运算符)进行操作。尽管 .net 确实具有非原始值类型,但大多数 .net 语言都保持相同运算符的约定(与 C 和 C++ 不同,后者用于->访问指向对象的成员并.访问结构的成员).用于“取消引用和访问成员”和“访问值类型成员”。

就个人而言,我不喜欢 Java 的“一切都是对象引用”设计,而 .net 决定让值类型和引用类型使用相同的.运算符来表示非常不同的事物并没有帮助,但它就是这样。

于 2013-03-05T23:03:59.787 回答