Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我的对象是指针?_C#_Oop - Fatal编程技术网

C# 为什么我的对象是指针?

C# 为什么我的对象是指针?,c#,oop,C#,Oop,我的问题涉及C#中对象的使用。我想我知道发生了什么,但我想知道为什么。出于我不想深入讨论的原因,我想用对象的当前数据(当前状态)创建对象的临时副本。所以我想我可以创建一个新对象,将其指定为原始对象,然后更改原始对象。在这一点上,我将有两个处于不同状态的对象。但实际情况是,复制的对象最终看起来与第一个完全相同。下面是一些代码来说明: Order o1 = new Order(); o1.property1 = "test 1"; Order o2 = new Order(); o2 = o1;

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

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

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

o1.property1 = "test 2";

但在代码末尾,o1和o2的属性1都设置为“测试2”。我想我意识到所有对象都只是指针,所以如果你改变一个,它就会改变另一个,但我不明白为什么会这样,或者为什么它有用。这里有没有我遗漏的一些基本的东西?还有,实现我想做的事情的最佳方式是什么?即:存储对象的状态,进行更改,然后在必要时还原。希望这是有意义的。

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

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


如上所述,理解是关键。

您所指的是值类型和引用类型之间的差异。显然,您的
Order
对象是一个引用类型,我假设它是一个类

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

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

您有两种解决方案:

  • 使用结构而不是类
  • 如果对象非常简单,请使用克隆,如果需要执行深度克隆,请使用自己的方法
    • C#中的对象变量是指向内存中特定对象的引用(而不是指针)。当你申报时

      Order o2 = new Order();
      
      您正在堆中创建一个新的Order对象,并将对该对象的引用分配给o2变量。当你说

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


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

      Java除了对象引用之外,没有任何非原始数据类型的概念;由于对对象引用所能做的几乎任何事情都涉及对其引用的对象进行操作,因此Java中的
      操作符。虽然.NET确实有非原始值类型,但是.NET语言维护了与C和C++不同的约定,它使用 > ->代码>访问指向对象的成员和 ./Cuth>以访问相同的 > .<代码>运算符,用于“引用引用和访问成员”。“访问值类型成员”


      就我个人而言,我不喜欢Java的“一切都是对象引用”设计,而.net决定让值类型和引用类型使用相同的
      运算符来表示完全不同的东西也没有帮助,但事实就是如此。

      关于你的问题

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


      一个简单的方法是简单地序列化对象,例如使用
      XMLSerializer
      。然后,如果要放弃更改,只需反序列化原始对象并用原始版本替换修改后的对象。

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

      请参阅相关文档。您需要了解引用类型与值类型。当您将o1分配给o2时,类是引用类型,实际上是将引用分配给o1,因此o1和o2都指向内存中的同一位置。这就是C#如何与refe一起工作的方式rence类型(即类)。谢谢Stan。关键是赋值o2=o1只是将引用赋值给对象,而不是对象中的值。除非您完全确定自己理解引用类型和值类型之间的区别,否则请不要使用结构。