如何在C#中处理托管和非托管对象

本文关键字:对象 处理 | 更新日期: 2023-09-27 18:22:44

all。我从来没有使用过析构函数或dispose,所以这对我来说是新的。我的任务是创建一个类,该类具有析构函数和dispose方法,并且具有自动增量的UInt64 Id属性和一个静态Dictionary<UInt64,MyClass>,该属性必须通过Id引用MyClass的所有live实例。

在搜索了如何正确使用它们之后,我最终做了以下事情:

public class MyClass : IDisposable
{
    private static Object Lock = new Object();
    private static Dictionary<UInt64, MyClass> LiveInstances = new Dictionary<UInt64, MyClass>();
    public UInt64 Id { get; private set; }
    public MyClass()
    {
        lock (Lock)
        {
            var newId = IncrementalId();
            if (newId == 0)
            {
                throw new ArgumentException("Reached MAX VAL");
            }
            Id = newId;
            LiveInstances.Add(Id, this);
        }
    }
    ~MyClass()
    {
       CleanUpNativeResources();
    }     
    public void Dispose()
    {
        lock (Lock)
        {
            CleanUpManagedResources();
            CleanUpNativeResources();
            GC.SuppressFinalize(this);
        }
    }
    protected virtual void CleanUpManagedResources()
    {
        LiveInstances.Remove(Id);
    }
    protected virtual void CleanUpNativeResources()
    {
    }
    private static UInt64 IncrementalId()
    {
        for (ulong i = 0; i <= Convert.ToUInt64(LiveInstances.Count) ; i++)
        {
            if (i != UInt64.MaxValue && !LiveInstances.ContainsKey(i + 1))
            {
                return i+1;
            }
        }
        return 0;
    }
}

现在,我的问题是如何处理对象无论我是否试图找到处理对象的示例,我都会发现这样的东西:

 // Code to dispose the managed resources of the class
 Console.WriteLine("Object disposed");

提前谢谢。

如何在C#中处理托管和非托管对象

托管资源将在某个时间点由垃圾收集器自动处理。非托管资源是像Filehandles这样的东西,通过执行Windows API调用来获得,该调用返回必须手动释放的Windows Handle。你没有任何需要手动处理的东西。如果不释放这些句柄,它们将在程序期间保持分配状态,但所有具有非托管资源的.Net类都会提供一个Finalizer(见下文),以确保它们在某个时刻正常释放。

(但是,如果您正在编写自己的文件处理类,却忘记在任何地方释放文件句柄,那么在程序退出之前,文件都将保持打开状态。)

通常情况下,这样的非托管资源将在两个地方释放:

Dispose()方法。这应该是处理非托管资源的正常方式。

终结器。这是最后的手段。如果一个类有终结器,则垃圾回收器在清理死对象时会调用它。如果程序员忘记调用Dispose(),任何具有非托管资源的类都应该有一个终结器来清理。

使用的基本Dispose模式如下所示:

class MyObject : IDisposable
{
    //indicates if dispose has already been called
    //private bool _disposed = false;
    //Finalize method for the object, will call Dispose for us
    //to clean up the resources if the user has not called it
    ~MyObject()
    {
        //Indicate that the GC called Dispose, not the user
        Dispose(false);
    }
    //This is the public method, it will HOPEFULLY but
    //not always be called by users of the class
    public void Dispose()
    {
        //indicate this was NOT called by the Garbage collector
        Dispose(true);
        //Now we have disposed of all our resources, the GC does not
        //need to do anything, stop the finalizer being called
        GC.SupressFinalize(this);
    }
    private void Dispose(bool disposing)
    {
        //Check to see if we have already disposed the object
        //this is necessary because we should be able to call
        //Dispose multiple times without throwing an error
        if (!disposed)
        {
            if (disposing)
            {
                //clean up managed resources
                components.Dispose();
            }
            //clear up any unmanaged resources - this is safe to
            //put outside the disposing check because if the user
            //called dispose we want to also clean up unmanaged
            //resources, if the GC called Dispose then we only
            //want to clean up managed resources
        }
    }
}