C#:对象变量应该分配为 null 吗?
在 C# 中,如果您已经使用完一个对象变量,是否有必要将它分配给 null,即使它无论如何都会超出范围?
In C#, is it necessary to assign an object variable to null
if you have finished using it, even when it will go out of scope anyway?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
不,这实际上可能是危险的并且容易出现错误(考虑一下有人可能稍后尝试使用它,而没有意识到它已被设置为空的可能性)。仅当有合理理由将某些内容设置为 null 时,才将其设置为 null。
No, and that could in fact be dangerous and bug-prone (consider the possibility that someone might try to use it later on, not realizing it had been set to null). Only set something to null if there's a logical reason to set it to null.
在把车推到湖边之前你应该关掉它吗?
不,这是一个常见的错误,但没有任何区别。您没有将对象设置为null,而只是对其进行一个引用 - 该对象仍然在内存中,并且仍然必须由垃圾收集器收集。
Should you turn off your car before pushing it to the lake?
No. It is a common mistake, but it doesn't make any difference. You aren't setting the object to null, just one reference to it - the object is still in memory, and must still be collected by the garbage collector.
在我看来,更重要的是对实现了 IDisposable 的对象调用 Dispose。
除此之外,将
null
分配给引用变量仅意味着您明确指示范围的结束 - 大多数时候,这只是早期的一些指令(例如,方法主体中的局部变量)——随着编译器/JIT 优化的时代,运行时很可能会做同样的事情,所以你真的不会从中得到任何东西。在某些情况下,例如静态变量等,其范围是应用程序级别,如果您使用完变量,则应将变量分配为 null ,以便对象将被垃圾收集。What matters more IMO is to call
Dispose
on objects that implementIDisposable
.Apart from that, assigning
null
to reference variables will just mean that you are explicitly indicating the end of scope — most of the time, it's just a few instructions early (for example, local variables in the method body) — with the era of compiler/JIT optimizations, its quite possible that runtime would do the same, so you really don't get anything out of it. In a few cases, such as static variables etc, whose scope is application level, you should assign a variable tonull
if you are done using it so that object will get garbage collected.这些回答中的大多数都有正确的答案,但原因却是错误的。
如果它是局部变量,则该变量将在方法结束时从堆栈中退出,因此它指向的对象将少一个引用。如果该变量是对该对象的唯一引用,则该对象可用于 GC。
如果您将变量设置为 null(许多这样做的人被教导在方法结束时这样做),那么您实际上可能会延长对象在内存中保留的时间,因为 CLR 会认为该对象不能被收集直到方法结束,因为它看到了对下面对象的代码引用。但是,如果省略 null 设置,CLR 可以确定在代码中的某个点之后不再出现对该对象的调用,并且即使该方法尚未完成,GC 也可以收集该对象。
Most of these responses have the right answer, but for the wrong reasons.
If it's a local variable, the variable will fall off the stack at the end of the method and therefore the object it was pointing to will have one less reference. If that variable was the only reference to the object, then the object is available for GC.
If you set the variable to null (and many who do were taught to do it at the end of the method) then you could actually wind up extending the time the object stays in memory because the CLR will believe that the object can't be collected until the end of the method because it sees a code reference to the object way down there. However, if you omit the setting of null the CLR can determine that no more calls for the object appear after a certain point in your code and, even though the method hasn't completed yet, the GC can collect the object.
分配给 null 通常是一个坏主意:
我唯一一次将某些内容分配给 null 来“清除”将不再使用的变量,而不是因为 null 实际上是我明确想要分配的值,是在两种可能的情况之一
这两种情况都不适用于局部变量,仅适用于成员,而且两者都很罕见。
Assigning to null is generally a bad idea:
The only time I would assign something to null to "clear" a variable that will no longer be used, rather than because null is actually a value I explicitly want to assign, is in one of the two possible cases:
Neither of these cases apply to local variables, only to members, and both are rare.
不会。当涉及到局部变量时,是否有对象的引用根本没有区别,重要的是是否会使用该引用。
在代码中放置额外的空赋值不会对性能造成太大影响,也根本不会影响内存管理,但它会在代码中添加无动机的语句,从而降低可读性。
垃圾收集器知道代码中最后一次使用该引用的时间,因此它可以在不再需要该对象时立即收集该对象。
例子:
No. When it comes to local variables it makes no difference at all if you have a reference to the object or not, what matters is if the reference will be used or not.
Putting an extra null assignment in the code doesn't hurt performance much, and it doesn't affect memory management at all, but it will add unmotivated statements to the code that makes it less readable.
The garbage collector knows when the reference is used the last time in the code, so it can collect the object as soon as it's not needed any more.
Example:
对于必须实现 IDisposable 的对象,作为实践,我在 IDisposable 的实现中将所有成员设置为 null。
很久以前,我发现这种做法极大地改善了 Windows Mobile 上运行的 .NET Compact Framework 应用程序的内存消耗和性能。我认为,与主 .NET Framework 相比,当时的 .NET Compact Framework 可能具有非常简约的垃圾收集器实现,并且在 IDisposable 实现中解耦对象的行为帮助 .NET Compact Framework 上的 GC 完成了它的任务。
这种做法的另一个原因是在对象上执行 IDisposable 后,实际上不希望任何东西尝试使用已处置对象上的任何成员。当然,理想情况下,您希望在尝试访问某个对象的任何函数时已释放的对象中出现 ObjectDisposeException,但用 NullReferenceException 代替它比没有异常要好。您想了解如何处理已释放对象的代码,因为滥用已释放的非托管资源可能会给应用程序带来很多麻烦。
注意: 我绝对不会提倡在对象上实现 IDisposable,除了将成员设置为 null 之外没有其他原因。我说的是当您出于其他原因需要实现 IDisposable 时,即您有实现 IDisposable 的成员或您的对象包装非托管资源。
For an object which has to implement IDisposable, as a practice I set all members to null in the implementation of IDisposable.
In the distant past I found this practice drastically improved the memory consumption and performance of a .NET Compact Framework application running on Windows Mobile. I think the .NET Compact Framework at the time probably had a very minimalistic implementation of the garbage collector compared to the main .NET Framework and the act of decoupling objects in the implementation of IDisposable helped the GC on the .NET Compact Framework do its thing.
An additional reason for this practice is after IDisposable has been executed on an object, it's actually undesirable for anything to attempt to use any of the members on a disposed object. Sure ideally you'd want an ObjectDisposedException out of an object which has been disposed when something attempts to access any of it's functions, but in place of that a NullReferenceException is better than no exception at all. You want to know about code messing with disposed objects as fooling around with unmanaged resources that have been released is something that can get an application into a lot of trouble.
NOTE: I'm definitely not advocating implementing IDisposable on an object for no other reason than to set members to null. I'm talking about when you need to implement IDisposable for other reasons, i.e. you have members which implement IDisposable or your object wraps unmanaged resources.
我想补充一点,据我所知,这只是 Visual Basic 单点版本的有效模式,甚至这也有些争议。 (IIRC 它仅适用于 DAO 对象。)
I'd just like to add that AFAIK this was only a valid pattern for one point release of Visual Basic, and even that was somewhat debatable. (IIRC it was only for DAO objects.)