Is this IDisposable implementation correct?

[亡魂溺海] 提交于 2019-12-01 01:07:57

You are accessing the managed object _disposeLock in the finalizer. It may have already been garbage-collected by then. Not sure what the implications of this would be as you are only using it to lock.

Thread-safety seems like overkill. I don't think you need to worry about contention between the GC thread and your application thread.

Otherwise it looks correct.

I can't really comment on the correctness of your code, but I question whether you'll find having the Disposable class at the base of your inheritance tree as flexible as it needs to be. It's won't be much use when you want to inherit from something you don't own. I think that IDispoasble is left as an interface because of the many different domains across which it might be used. Providing a concrete implementation at the foot of the inheritance hierarchy would be... limiting.

EDIT Yes, I misread the portion about separating disposing managed and unmanaged resources (still on first cup of coffee).

However the lock is still almost certainly not necessary. Yes, during a passive dispose the code will be running on the finalizer thread which is different than the thread it originally ran on. However if the object is being finalized in this fashion the CLR has already determined there are no existing references to this object and hence collected it. So there is no other place which can be calling your dispose at that time and hence there is no reason for a lock.

A couple of other style comments.

Why make the methods abstract? By doing so you are forcing derived classes to implement methods to dispose of managed and unmanaged resources even if they don't have any to dispose. True there is no point in deriving from this class if you don't have anything to dispose. But I think it's fairly common to only have one or the other but not both. I would make them virtual vs. abstract.

Also you prevent double dispose but you do nothing to warning the developer that they are double disposing an object. I realize the MSDN documentation says that double dispose should be essentially a no-op but at the same time under what circumstances should this be legal? In general it's a bad idea to access an object after it's been disposed. A double dispose necessitates a disposed object being reused and is likely a bug (this can happen if finalization is not suppressed in an active dispose but that's also a bad idea). If I were implementing this I would throw on double dispose to warn the developer they were using an object incorrectly (that is using it after it was already disposed).

If you are concerned about the thread safety then I'd use the lightweight interlocked operations rather than a heavyweight lock:

class MyClass: IDispose {
  int disposed = 0;

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

  public virtual void Dispose(bool disposing)
  {
     if (0 == Thread.InterlockedCompareExchange(ref disposed, 1, 0))
     {
       if (disposing)
       {
          // release managed resources here
       }
       // release unmanaged resources here
     }
  }

  ~MyClass()
  {
    Dispose(false);
  }
} 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!