在析构函数中使用 null 条件运算符是不好的做法吗?
Is using the null conditional operator in a destructor bad practice?
我有一个 class 和一个 析构函数 我从中得到一个 空引用异常 因为我销毁的变量是有时 null
.
在析构函数中使用空条件运算符是否合适?
我什至不确定这是否是对析构函数本身的适当使用,因为它不是用于处理调用它的实际对象,而是它的一个变量。
~clsSAPSettings()
{
mtbTemp?.Close();
}
这段代码是从 VB6 转换而来的,所以我想弄清楚如何处理这个问题。欢迎任何信息。
编辑: class mtbTemp
属于法器 IDisposable
但 没有一个finaliser/desctructor。它只是关闭 ORM 模型中使用的连接。
对于经过详细解释后的任何人,我找到了一个很好的答案,Proper use of the IDisposable interface,它详细介绍了终结器的使用以及垃圾收集的实际工作原理。
当您关闭流或其他非托管对象时,您应该使用 Dispose
模式,而不是析构函数。你永远不知道那个析构函数什么时候会触发。
关于在析构函数中使用 null 条件运算符:我认为运算符本身没有问题。我会引用其他可能已经被破坏或正在破坏的对象。
请不要在终结器中使用任何引用类型字段:GC(垃圾收集器)收集它们的顺序是不可预测 这就是为什么
~clsSAPSettings()
{
mtbTemp?.Close();
}
代码可以很好地被GC执行如下:
- 收集
mtbTemp
个实例
- 开始收集
this
个实例:
- 致电
~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();
}
这里的问题不是 null 条件用法。这本身并不存在任何问题。
最大的问题是在终结器中你不应该接触任何其他对象。当终结器触发时,您的对象就烤好了。您不再对 mtbTemp
的生命周期有任何保证,包括它是否已经被垃圾回收,因此您 不应触摸它 。它可能会起作用;它可能会导致暂时的复活,或者它可能会可怕地崩溃。
执行此类操作的正确位置是 IDisposable.Dispose
。在 Dispose
方法中,这绝对没问题:
public void Dispose() // where your class : IDisposable
{
mtbTemp?.Close();
mtbTemp = null;
}
您可能根本不需要终结器。它们非常罕见。
我有一个 class 和一个 析构函数 我从中得到一个 空引用异常 因为我销毁的变量是有时 null
.
在析构函数中使用空条件运算符是否合适?
我什至不确定这是否是对析构函数本身的适当使用,因为它不是用于处理调用它的实际对象,而是它的一个变量。
~clsSAPSettings()
{
mtbTemp?.Close();
}
这段代码是从 VB6 转换而来的,所以我想弄清楚如何处理这个问题。欢迎任何信息。
编辑: class mtbTemp
属于法器 IDisposable
但 没有一个finaliser/desctructor。它只是关闭 ORM 模型中使用的连接。
对于经过详细解释后的任何人,我找到了一个很好的答案,Proper use of the IDisposable interface,它详细介绍了终结器的使用以及垃圾收集的实际工作原理。
当您关闭流或其他非托管对象时,您应该使用 Dispose
模式,而不是析构函数。你永远不知道那个析构函数什么时候会触发。
关于在析构函数中使用 null 条件运算符:我认为运算符本身没有问题。我会引用其他可能已经被破坏或正在破坏的对象。
请不要在终结器中使用任何引用类型字段:GC(垃圾收集器)收集它们的顺序是不可预测 这就是为什么
~clsSAPSettings()
{
mtbTemp?.Close();
}
代码可以很好地被GC执行如下:
- 收集
mtbTemp
个实例 - 开始收集
this
个实例: - 致电
~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();
}
这里的问题不是 null 条件用法。这本身并不存在任何问题。
最大的问题是在终结器中你不应该接触任何其他对象。当终结器触发时,您的对象就烤好了。您不再对 mtbTemp
的生命周期有任何保证,包括它是否已经被垃圾回收,因此您 不应触摸它 。它可能会起作用;它可能会导致暂时的复活,或者它可能会可怕地崩溃。
执行此类操作的正确位置是 IDisposable.Dispose
。在 Dispose
方法中,这绝对没问题:
public void Dispose() // where your class : IDisposable
{
mtbTemp?.Close();
mtbTemp = null;
}
您可能根本不需要终结器。它们非常罕见。