为什么不使用ref参数,复制后原对象变了?在工作中,我们遇到了一个问题,即在我们通过方法发送副本后,原始对象发生了变异。我们确实通过在原始类中使用IClonable找到了解决方法,但我们无法首先找到它发生的原因。我们编写了这个示例代码来重现问题(类似于我们的原始代码),希望有人能解释为什么会这样。publicpartialclassClassRefTest:System.Web.UI.Page{protectedvoidPage_Load(objectsender,EventArgse){varmyclass=newMyClass();变种副本=我的班级;myclass.Mystring="jadajadajada";Dal.DoSomeThing(复制);lit.Text=myclass.Mystring;//文本应该是jadajadajada,但最终被引用}}publicclassMyClass{publicstringMystring{get;放;}}publicstaticclassDal{publicstaticint?DoSomeThing(MyClassdaclass){daclass.Mystring="referenced";返回空值;如您所见,在DoSomething()方法中,我们没有使用任何ref参数,但lit.Text最终仍被引用。为什么?解释它是如何工作的总是很有趣。当然,我的解释无法与JonSkeet或JosephAlbahari的才华相提并论,但我会尝试。在过去的C编程时代,掌握指针的概念是使用该语言的基础。经过这么多年我们称它们为引用,但它们仍然是...美化指针,如果您了解它们的工作原理,您就是半个程序员(开玩笑)什么是引用?我会给你一个非常简短的答案。它是一个存储在变量中的数字,代表数据在内存中的地址。为什么我们需要参考?因为处理单个数字非常简单,我们可以用它来读取数据的内存区域,而不是用我们的代码移动整个对象及其所有字段。那么,当我们写varmyclass=newMyClass();时会发生什么?我们都知道这是对MyClass类的构造函数的调用,但是对于Framework来说也是请求提供一块内存区域,实例的值(属性,字段,以及其他内部管理信息)存在并且存在于一个特定的时间点。假设MyClass需要100个字节来存储它需要的所有内容。框架以某种方式搜索计算机内存并假设它在内存中找到一个由地址4200标识的位置。值(4200)是它分配给varmyclass的值,它是指向内存的指针(oops),它是对对象实例的引用)现在打电话会发生什么?变种副本=我的班级;没什么特别的。复制变量获得与myclass(4200)相同的值。但是两个变量都引用相同的内存区域,因此使用一个或另一个没有任何区别。内存区域(MyClass的实例)仍然在我们想象的内存地址4200处。myclass.Mystring="jadajadajada";它使用引用值作为基值找到属性占用的内存区域,并将其值设置为保存文字字符串的内部区域。如果我可以用指针来类比,就像你使用基本内存(4200),添加一个偏移量以找到代表属性MyString的引用在我们的对象实例占用的100字节边界内的位置。假设MyString引用了内存区域的前42个字节。将42添加到4200得到4242,这是存储对文字“jadajadajada”的引用的点。Dal.DoSomeThing(副本);这就是问题所在(您遇到问题的地方)。当你传递copy变量时,不要以为框架会反复搜索内存区域,将原区域的所有内容复制到新区域中。不,这几乎是不可能的(想想如果MyClass包含的属性是另一个类的实例等......它永远不会停止。)所以传递给DoSomeThing方法的值再次是参考值4200。value会自动分配给声明为DoSomething的输入参数的局部变量daclass(就像您之前明确使用varcopy=myclass;所做的那样)。至此很明显,在daClass上使用daClass的任何操作都作用于原始实例占用的同一内存区域,当代码返回到起点时,您将看到结果。请技术专家用户见谅。特别是我对“内存地址”一词的随意和不精确的使用。这是正常的,因为你的MyClass是一个引用类型,所以你传递的是对原始数据的引用而不是数据本身,这就是为什么这里的预期行为是将C#的引用类型的引用类型解释为A类型,其值是对适当数据的引用,而不是数据本身MSDN的文档对此非常清楚。值类型默认作为副本传递,对象默认作为引用传递。C#中的方法我在这里看到两个问题...制作对象的副本varcopy=myClass;不复制-它真正做的是创建对myClass的第二个引用(“指针”)(命名变量“copy”具有误导性)。所以你有myClass和copy指向同一个对象。要复制你必须做的:varcopy=newMyClass(myClass);请注意,我创建了一个新对象。通过引用传递当值类型变量在没有引用的情况下传递时,接收方法不能更改该变量。示例:DoSomething(intfoo)–DoSomething不能影响foo本身的值。当您使用ref传递值类型变量时,您可以更改变量示例:DoSomething(refintfoo)-如果DoSomething更改foo,它将保持更改。当你传递一个没有引用的对象时,你可以更改对象的数据,但不能更改对象的引用。以上是C#学习教程:为什么复制后原来的对象变了,而不是使用ref参数?如果分享的内容对你有用,需要进一步了解C#学习教程,希望你多多关注——voidDoSomething(MyClassmyClass){myClass.myString="ABC"//字符串设置到ABCmyClass=newMyClass();//没有影响——甚至可能不允许}当一个对象被ref传递时,对象的数据可以改变,对象的引用也可以改变。voidDoSomething(refMyClassmyClass){myClass.myString="ABC"//字符串设置为ABCmyClass=newMyClass();//由于myClass已更改,字符串现在为""}本文来自网络合集,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:
