您需要释放对象并将其设置为空吗?

您需要释放对象并将其设置为空吗?

您需要释放对象并将其设置为NULL吗?或者垃圾收集器会在它们超出作用域时清除它们吗?



杨魅力
浏览 497回答 3
3回答

小唯快跑啊

对象在C#中从不超出作用域,就像它们在C+中所做的那样。当垃圾收集器不再使用时,垃圾收集器会自动处理它们。这是一种比C+更复杂的方法,在C+中,变量的范围完全是确定性的。CLR垃圾收集器主动遍历所有已创建的对象,并计算出它们是否被使用。对象可以在一个函数中“超出作用域”,但如果返回其值,则GC将检查调用函数是否保留返回值。将对象引用设置为null没有必要,因为垃圾收集是通过计算其他对象引用的对象来完成的。在实践中,你不必担心破坏,它只是起作用了,而且很棒:)Dispose必须对实现的所有对象调用IDisposable当你和他们一起工作完之后。通常您会使用using用这样的对象阻止:using&nbsp;(var&nbsp;ms&nbsp;=&nbsp;new&nbsp;MemoryStream())&nbsp;{ &nbsp;&nbsp;//...}编辑在可变范围内。Craig询问变量范围是否对象生存期有任何影响。为了正确地解释CLR的这个方面,我需要从C+和C#中解释一些概念。实际变量范围在这两种语言中,变量只能在定义的相同范围内使用-类、函数或用大括号括起来的语句块。然而,不同之处在于,在C#中,不能在嵌套块中重新定义变量。在C+中,这是完全合法的:int&nbsp;iVal&nbsp;=&nbsp;8;//iVal&nbsp;==&nbsp;8if&nbsp;(iVal&nbsp;==&nbsp;8){ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;iVal&nbsp;=&nbsp;5; &nbsp;&nbsp;&nbsp;&nbsp;//iVal&nbsp;==&nbsp;5}//iVal&nbsp;==&nbsp;8但是,在C#中,您会得到一个编译器错误:int&nbsp;iVal&nbsp;=&nbsp;8;if(iVal&nbsp;==&nbsp;8)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;iVal&nbsp;=&nbsp;5;&nbsp;//error&nbsp;CS0136:&nbsp;A&nbsp;local&nbsp;variable&nbsp;named&nbsp;'iVal'&nbsp;cannot&nbsp;be&nbsp;declared&nbsp;in&nbsp;this&nbsp;scope&nbsp;because&nbsp;it&nbsp;would&nbsp;give&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;different&nbsp;meaning&nbsp;to&nbsp;'iVal',&nbsp;which&nbsp;is&nbsp;already&nbsp;used&nbsp;in&nbsp;a&nbsp;'parent&nbsp;or&nbsp;current'&nbsp;scope&nbsp;to&nbsp;denote&nbsp;something&nbsp;else}如果您查看生成的msil-函数使用的所有变量都是在函数的开头定义的,这是有意义的。看看这个函数:public&nbsp;static&nbsp;void&nbsp;Scope()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;iVal&nbsp;=&nbsp;8; &nbsp;&nbsp;&nbsp;&nbsp;if(iVal&nbsp;==&nbsp;8)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;iVal2&nbsp;=&nbsp;5; &nbsp;&nbsp;&nbsp;&nbsp;}}下面是生成的IL。注意,在if块中定义的iVal2实际上是在函数级别定义的。这实际上意味着,就变量生存期而言,C#只具有类和函数级别的作用域。.method&nbsp;public&nbsp;hidebysig&nbsp;static&nbsp;void&nbsp;&nbsp;Scope()&nbsp;cil&nbsp;managed{ &nbsp;&nbsp;//&nbsp;Code&nbsp;size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;19&nbsp;(0x13) &nbsp;&nbsp;.maxstack&nbsp;&nbsp;2 &nbsp;&nbsp;.locals&nbsp;init&nbsp;([0]&nbsp;int32&nbsp;iVal, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;int32&nbsp;iVal2, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;bool&nbsp;CS$4$0000)//Function&nbsp;IL&nbsp;-&nbsp;omitted}&nbsp;//&nbsp;end&nbsp;of&nbsp;method&nbsp;Test2::ScopeC+作用域和对象生存期每当在堆栈上分配的C+变量超出作用域时,它就会被销毁。请记住,在C+中,您可以在堆栈或堆上创建对象。当您在堆栈上创建它们时,一旦执行离开范围,它们就会从堆栈中弹出并被销毁。if&nbsp;(true)&nbsp;{ &nbsp;&nbsp;MyClass&nbsp;stackObj;&nbsp;//created&nbsp;on&nbsp;the&nbsp;stack &nbsp;&nbsp;MyClass&nbsp;heapObj&nbsp;=&nbsp;new&nbsp;MyClass();&nbsp;//created&nbsp;on&nbsp;the&nbsp;heap &nbsp;&nbsp;obj.doSomething();}&nbsp;//<--&nbsp;stackObj&nbsp;is&nbsp;destroyed//heapObj&nbsp;still&nbsp;lives当在堆上创建C+对象时,必须显式销毁它们,否则就是内存泄漏。但是,堆栈变量没有这样的问题。C#对象生命周期在CLR中,对象(即引用类型)是总在托管堆上创建。对象创建语法进一步加强了这一点。考虑一下这个代码片段。MyClass&nbsp;stackObj;在C+中,这将创建一个MyClass并调用其默认构造函数。在C#中,它将创建对类的引用MyClass这并不意味着什么。创建类实例的唯一方法是使用new操作员:MyClass&nbsp;stackObj&nbsp;=&nbsp;new&nbsp;MyClass();在某种程度上,C#对象非常类似于使用newC+中的语法-它们是在堆上创建的,但与C+对象不同,它们是由运行时管理的,因此您不必担心对它们进行析构。因为对象是总在堆中,对象引用(即指针)超出作用域的事实变得毫无意义。在确定是否要收集对象时,涉及的因素比简单地存在对象的引用所涉及的因素更多。C#对象引用乔恩·斯基特Java中的对象引用比较连接到气球上的字符串,气球是对象。同样的类比也适用于C#对象引用。它们只是指向包含对象的堆的位置。因此,将其设置为NULL对象生存期没有直接影响,气球继续存在,直到GC“弹出”它。按照气球的类比,一旦气球没有附加条件,它就可以被摧毁,这似乎是合乎逻辑的。事实上,这正是引用计数对象在非托管语言中的工作方式。但是,这种方法对循环引用没有很好的效果。想象一下,两个气球由一根绳子连接在一起,但没有一个气球与任何其他气球相连。在简单的参考计数规则下,它们都继续存在,即使整个气球组是“孤儿”。NET对象很像屋顶下的氦气气球。当屋顶打开(GC运行)NETGC使用分代GC和标记和扫描的组合。分代方法包括运行时倾向于检查最近分配的对象,因为它们更可能未使用;标记和扫描涉及运行时遍历整个对象图,并计算出是否有未使用的对象组。这充分地处理了循环依赖问题。此外,.NET GC在另一个线程上运行(即所谓的终结器线程),因为它有相当多的工作要做,在主线程上这样做会中断程序。

临摹微笑

就像其他人说的,你绝对想打电话给Dispose如果类实现IDisposable..我对此采取了相当强硬的立场。有些人可能会声称Dispose在……上面DataSet例如,因为他们拆掉了它,看到它没有做任何有意义的事情,所以是毫无意义的。但是,我认为这个论点中有很多谬误。朗读,阅读这,这个值得尊敬的人就这个问题进行有趣的辩论。那就读读我的推理这里为什么我认为杰弗里·里克特在错误的阵营。现在,关于是否应该将引用设置为null..答案是否定的。让我用下面的代码来说明我的观点。public&nbsp;static&nbsp;void&nbsp;Main(){ &nbsp;&nbsp;Object&nbsp;a&nbsp;=&nbsp;new&nbsp;Object(); &nbsp;&nbsp;Console.WriteLine("object&nbsp;created"); &nbsp;&nbsp;DoSomething(a); &nbsp;&nbsp;Console.WriteLine("object&nbsp;used"); &nbsp;&nbsp;a&nbsp;=&nbsp;null; &nbsp;&nbsp;Console.WriteLine("reference&nbsp;set&nbsp;to&nbsp;null");}那么你认为什么时候被引用的对象a是否有资格领取?如果你说打完电话a = null那你就错了。如果你说在Main方法完成,那么您也错了。正确的答案是,它有时有资格领取。期间打电话给DoSomething..这是对的。它有资格以前引用设置为null甚至在呼吁DoSomething完成。这是因为即使对象引用仍然是根,JIT编译器也可以识别对象引用何时不再取消引用。
打开App,查看更多内容
随时随地看视频慕课网APP