C# 在析构函数中使用null条件运算符是一种错误的做法吗?
我有一个带有析构函数的类,我从中得到了一个null引用异常,因为我销毁的变量有时是C# 在析构函数中使用null条件运算符是一种错误的做法吗?,c#,.net,vb6,C#,.net,Vb6,我有一个带有析构函数的类,我从中得到了一个null引用异常,因为我销毁的变量有时是null 在析构函数中使用null条件运算符是否合适 我甚至不确定这是否是析构函数本身的适当用法,因为它不是用来处理调用它的实际对象,而是它的一个变量 ~clsSAPSettings() { mtbTemp?.Close(); } 这段代码是从VB6转换而来的,所以我试图找出如何处理这个问题。欢迎提供任何信息 编辑:该类mtbTemp属于implementsIDisposable,但没有定稿器/解构器
null
在析构函数中使用null条件运算符是否合适
我甚至不确定这是否是析构函数本身的适当用法,因为它不是用来处理调用它的实际对象,而是它的一个变量
~clsSAPSettings()
{
mtbTemp?.Close();
}
这段代码是从VB6转换而来的,所以我试图找出如何处理这个问题。欢迎提供任何信息
编辑:该类
mtbTemp
属于implementsIDisposable
,但没有定稿器/解构器。它只是关闭ORM模型中使用的连接
对于任何人来说,在详细解释之后,我发现了一个很好的答案,它详细介绍了finalizer的使用以及垃圾收集的实际工作方式。当您关闭流或其他非托管对象时,应该使用
Dispose
模式,而不是析构函数。你永远不知道什么时候毁灭者会开火
关于在析构函数中使用null条件运算符:我认为运算符本身没有问题。我不会引用其他可能已经被销毁或正在销毁的对象。请不要在终结器中使用引用类型的任何字段:GC(垃圾收集器)收集它们的顺序是不可预测的,这就是为什么
~clsSAPSettings()
{
mtbTemp?.Close();
}
GC可以很好地执行以下代码:
mtbTemp
实例~clsSAPSettings()
mtbTemp?.Close()代码>即调用收集(销毁)实例的方法
IDisposable
界面:
public class clsSAPSettings: IDisposable {
private MyTemp mtbTemp;
...
protected virtual void Dispose(bool disposing) {
if (disposing) {
mtbTemp?.Close();
GC.SuppressFinalize(this);
}
}
public void Dispose() {
Dispose(true);
}
//TODO: do you really want finalizer?
~clsSAPSettings() {
Dispose(false);
}
}
考虑:
~clsSAPSettings()
{
mtbTemp?.Close();
}
这里的问题不是空条件用法。这本身并不存在任何问题
最大的问题是,在终结器中,您不应触摸任何其他对象。当终结器触发时,对象是toast。您不再对mtbTemp
的寿命有任何保证,包括它是否已被垃圾收集,因此不应触摸它。它可能会起作用;它可能会导致暂时的复活,也可能会可怕地崩溃
这样做的正确位置是IDisposable.Dispose
。在Dispose
方法中,这绝对可以:
public void Dispose() // where your class : IDisposable
{
mtbTemp?.Close();
mtbTemp = null;
}
您可能根本不需要终结器。它们极其罕见。如果
mtbTemp
的类型是另一种托管类型,则此代码是错误的。它属于IDisposable.Dispose
,而不是finalizer@Oystein不,不是。Dispose
模式是。否,析构函数用于处理非托管资源,而不是托管资源。如果您有一个IntPtr
或类似的对象作为某个非托管对象的句柄,那么除了一次性模式之外,析构函数也是关闭该对象的一个位置。你不应该为这类事情调用其他对象。SerialPort类的析构函数,正确,而不是CommunicationHandler的析构函数。只有当你接触到没有析构函数的对象时才是“安全的”,但你必须非常确定这始终是真的。一般来说,永远不要触摸任何对象。观察:如果您已经在终结器中,那么禁止终结器是没有意义的,因此GC.SuppressFinalize(this)
可以移动到if(disposing){…}
分支,这会暴露出我们实际上没有在终结器中执行任何操作,这说明我们不需要finalizer@Marc格雷威尔:谢谢你!接得好GC.SuppressFinalize(这个)
确实应该在if(disposing){…}
中,谢谢你的回答,它的信息量很大。我有一个问题,为什么不从终结器触发mtbTemp的处置(close())?当这个对象被销毁时,该对象(连接)不应该被关闭吗?@George K:我调用Dispose(false)代码>(不是true
),因为mtbTemp
实例可以很好地收集(即销毁),这就是为什么我们不能调用此类实例的任何方法。请在我的回答中看看这样的场景(“1.收集mtbTemp实例…”)。@George K:GC形成要销毁的对象集合,然后按任意顺序销毁它们。这就是为什么我们不能在终结器中确定mtbTemp
没有被销毁。