Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在析构函数中使用null条件运算符是一种错误的做法吗?_C#_.net_Vb6 - Fatal编程技术网

C# 在析构函数中使用null条件运算符是一种错误的做法吗?

C# 在析构函数中使用null条件运算符是一种错误的做法吗?,c#,.net,vb6,C#,.net,Vb6,我有一个带有析构函数的类,我从中得到了一个null引用异常,因为我销毁的变量有时是null 在析构函数中使用null条件运算符是否合适 我甚至不确定这是否是析构函数本身的适当用法,因为它不是用来处理调用它的实际对象,而是它的一个变量 ~clsSAPSettings() { mtbTemp?.Close(); } 这段代码是从VB6转换而来的,所以我试图找出如何处理这个问题。欢迎提供任何信息 编辑:该类mtbTemp属于implementsIDisposable,但没有定稿器/解构器

我有一个带有析构函数的类,我从中得到了一个null引用异常,因为我销毁的变量有时是
null

在析构函数中使用null条件运算符是否合适

我甚至不确定这是否是析构函数本身的适当用法,因为它不是用来处理调用它的实际对象,而是它的一个变量

~clsSAPSettings()
{

    mtbTemp?.Close();
}
这段代码是从VB6转换而来的,所以我试图找出如何处理这个问题。欢迎提供任何信息


编辑:该类
mtbTemp
属于implements
IDisposable
,但没有定稿器/解构器。它只是关闭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
    没有被销毁。