Update: My initial answer didn’t really answer the question, so here is another try ...
To solve the root problem, developers forget to drop ObjectDisposedExceptions
, perhaps automatic testing of the device will do the trick. If you want to strictly comply with the requirement that all methods / properties immediately throw an ObjectDisposedException
if Dispose
has already been called, you can use the following unit test. Just specify the assemblies you want to test. You will probably need to change the IsExcluded
method as needed, and object bullying may not work in all cases.
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using MbUnit.Framework; using Moq; [TestFixture] public class IDisposableTests { [Test] public void ThrowsObjectDisposedExceptions() { var assemblyToTest = Assembly.LoadWithPartialName("MyAssembly");
The original answer . It doesn't seem like there is something like NotifyPropertyWeaver for IDisposable
, so if you want you to need to create a similar project yourself. You can save yourself a little work by having the base class Disposable, as in this blog post . Then you have only one liner at the top of each method: ThrowExceptionIfDisposed()
.
However, none of the possible solutions seems right or seems necessary. In general, throwing an ObjectDisposedException
not required, which is often. I did a quick search in Reflector, and an ObjectDisposedException
is ObjectDisposedException
directly by only 6 types in BCL, and for a sample outside BCL System.Windows.Forms
only one type that throws: Cursor
when receiving Handle.
Basically, you only need to throw an ObjectDisposedException
if your object call fails because Dispose
has already been called, for example, if you set some field to null, which is necessary for a method or property. ObjectDisposedException
will be more informative than a random NullReferenceException
, but if you do not clear unmanaged resources, there is usually no need to set the empty string to zero. Most of the time, if you just call Dispose on other objects, you need to throw an ObjectDisposedException
.
Here is a trivial example: you can explicitly throw an ObjectDisposedException
:
public class ThrowObjectDisposedExplicity : IDisposable { private MemoryStream stream; public ThrowObjectDisposedExplicity() { this.stream = new MemoryStream(); } public void DoSomething() { if (this.stream == null) { throw new ObjectDisposedException(null); } this.stream.ReadByte(); } protected virtual void Dispose(bool disposing) { if (disposing) { if (this.stream != null) { this.stream.Dispose(); this.stream = null; } } } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } }
With the above code, although there really is no need to set the stream to null. You can simply rely on MemoryStream.ReadByte()
to throw an ObjectDisposedException
on it, as in the code below:
public class ThrowObjectDisposedImplicitly : IDisposable { private MemoryStream stream; public ThrowObjectDisposedImplicitly() { this.stream = new MemoryStream(); } public void DoSomething() {
The first strategy to set the thread to null may make sense in some cases, for example, if you know that the object will throw an exception if Dispose is called multiple times. In this case, you want to be protected and make sure that your class does not throw an exception on multiple Dispose
calls. Also, I can't think of any other cases where you need to set the fields to zero, which will probably require throwing ObjectDisposedExceptions
.
Throwing an ObjectDisposedException
not often required and should be carefully considered, so the tool you need is probably not needed. Use the Microsoft libraries as an example; see which methods actually implement throw ObjectDisposedException
when the type implements IDisposable
.
Note. GC.SuppressFinalize(this);
is not strictly necessary because there is no finalizer, but it has stayed there since the subclass can implement the finalizer. If the class was marked as sealed
, then GC.SupressFinalize
could be safely removed.