【问题标题】:Correct way to dispose object in C#?在 C# 中处理对象的正确方法?
【发布时间】:2015-04-20 00:25:29
【问题描述】:

您好,我是这个伟大社区的新手,我有第一个问题。希望这个在正确的地方(我希望我的英语是正确的):

我是新手开发人员,我必须改进 C# 应用程序,所以我找到了这段代码,我想知道这是否是正确的方法

ObjClass obj = new ObjClass();
obj.SomeText = TextBox1.Text;
obj.SomeNumber = Convert.ToInt32(TextBox2.Text);

ObjClass的定义如下:

    using System;

namespace SomeObject
{
    public class ObjClass : IDisposable
    {
        public string SomeText { get; set; }
        public int SomeNumber{ get; set; }

        public void Dispose()
        {
            GC.SuppressFinalize(this); 
        }
    }
}

然后在使用对象后,完成或处置对象的代码如下:

if(obj.SomeNumber != null)
{
    //doing something else
    obj.Dispose();
}

【问题讨论】:

标签: c# dispose


【解决方案1】:

正确的方法是根本不编写Dispose 函数。充其量你只是在捆绑 GC,阻止它释放你的对象,直到它在 GUI 线程上调用它(减慢它的速度)并得到它已经运行的确认。在最坏的情况下,你写得和以前一样糟糕,最终导致潜在的内存泄漏。

现在,如果您直接在对象中处理本机内存或资源(这种情况很少见,您可以避免处理大部分并将其留给 .NET),编写终结器的正确方法(即您缺少的部分) !) 是:

public class Base: IDisposable
{
    private bool disposed = false;

    //Implement IDisposable.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Free other state (managed objects).
            }
            // Free your own state (unmanaged objects).
            // Set large fields to null.
            disposed = true;
        }
    }

    // Use C# destructor syntax for finalization code.
    ~Base()
    {
        // Simply call Dispose(false).
        Dispose (false);
    }
}

您的代码只是阻止终结器运行,此代码在终结器中调用 Dispose(false)(即当 GC 确定您的对象无用并尝试释放它时)或在您自己调用 Dispose() 时调用 Dispose(true) (然后阻止 GC 调用终结器,这样您就不会处理两次)。

至于你如何使用它,这是正确的方法:

using(var obj = new Base())
{
   // do whatever you want
   // obj.Dispose() will automatically be called at the end of scope
}

在功能上等同于:

try
{ 
   var obj = new Base();  
   // use the object
} 
finally 
{
   // always called, even during exception stack unwinding  
   obj.Dispose();
}

再一次,正确的方法是不要写Dispose。每次您需要这样做时,框架未能为您提供正确的工具以留在受管理的世界中。现在这种情况越来越少了。

【讨论】:

    【解决方案2】:

    如果一个类是一次性的,确保它被丢弃的最佳方法是使用using 块。

    using(var foo = new ObjClass())
    {
        // do something
    }
    

    这将确保即使发生异常也会释放对象。

    【讨论】:

      【解决方案3】:

      欢迎来到 IDisposable 的精彩世界!我认为这是 2 个问题:

      1) ObjClass 的实现是否正确 - 是否需要实现 IDisposable
      一个类应该实现 IDisposable:
      a.因为它拥有非托管资源。如果适用,请使用“标准 IDispose 实现”(搜索即可找到)。 这种情况实际上很少见。 这个类似乎不是这种情况 - 它只有两个成员是托管的。
      b.因为该类包含实现 IDisposable 的托管对象,并且您希望您的类的用户能够控制何时释放这些管理对象持有的资源。请注意,这与是否释放资源无关——它们最终总是会被 GC 释放——但是通过提供 IDisposable 您可以让您的班级用户控制何时发生这种情况。一个很好的例子是一个持有托管 Socket 对象的类。 Socket 实现了 IDisposable,它将关闭端口。通过您的类实现 IDisposable 并在其 Dispose 方法中处理套接字,您允许您的类用户控制套接字何时关闭。
      以上都不是或 b。这里的类是这样写的,所以在这里实现 IDisposable 似乎是错误的。

      2) ObjClass 实例的使用方式是否正确?
      处理完一个对象后,可以显式调用 Dispose - 这样做并没有什么绝对不正确的。但是 using 语句是执行此操作的首选方式。重要的是(如另一个答案中所述)一个 using 块在幕后包括一个 try/catch 和一个 finally 来处理对象 - 这很重要。如果你不使用“使用”,你应该有一个 try catch 来处理对象,如果有异常。

      【讨论】:

        猜你喜欢
        • 2011-12-13
        • 2011-04-24
        • 1970-01-01
        • 1970-01-01
        • 2012-10-10
        • 1970-01-01
        • 1970-01-01
        • 2011-07-05
        • 1970-01-01
        相关资源
        最近更新 更多