How to find out an object has disposed?
Solution 1
Well, according to Reflector, CancellationTokenSource
has an internal IsDisposed
method that could've told you, but since it's internal, you're not supposed to call it.
In any case, if one thread yanks out data structures and objects other threads depend on, then don't do that. Fix your code and leave those objects live for the duration of their need.
In other words, wait for those other threads to finish needing the CancellationTokenSource
before you dispose of it.
Solution 2
The proper course of action would be for the creators of some Disposable objects to go slightly against Microsoft's "rule" that performing any action on a disposed object should throw an exception, and instead follow the more general rule that an exception should be thrown any time a method's post-conditions can't be met. If the purpose of a Cancel method is to ensure that nobody will continue to regard a job as being live, and even before the Cancel method is called everyone regards the job as being dead, then the post-condition for the method is satisfied regardless of whether the object is disposed.
Generally, code outside a well-designed object shouldn't need to query whether it's been disposed, except possibly to assert that it has been. Instead, the object itself should provide methods whose meaning on a disposed object would be clear and unambiguous. Those methods might internally use an IsDisposed flag, but would have to use whatever locking was necessary to prevent race conditions. In general, the pattern
if (!myThing.isDisposed) myThing.DoSomething();
is an indication that myThing should really support a DoSomethingIfNotDisposed method (possibly called TryDoSomething). If you can't do that, my inclination might be to write your own DoSomethingIfNotDisposed extension method and use a Try/Catch to stifle an ObjectDisposedException (or whatever particular exception the object would throw).
Solution 3
Inherit your class and add the property:
class MyCancellationTokenSource: CancellationTokenSource
{
public bool MyIsDisposed { get; private set; }
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
MyIsDisposed = true;
}
}
Solution 4
check if the object is disposed before using it.
Still not the best design pattern. however here is what I use do determine if an object is disposed.
if (!object.IsDisposed) object.DoSomething();
or
public string DoSomething()
{
if (this.IsDisposed) return null;
}
if that does not work, you may try adding an IsDisposed flag and overriding the dispose method. And setting that to true in your own code.
Comments
-
Xaqron over 3 years
I have a multi-threaded application and a
CancellationToken
is used as a shared object. Every thread can trigger it to tell the other threads the job is cancelled. Then one thread does the clean-up and disposes every object like thisCancellationToken
. Then if a thread tries to use it, an exception is raised:The CancellationTokenSource has been disposed.
How can I find out an object is disposed before using it?
-
Xaqron about 13 yearsI have one but the problem is race condition. Maybe a wait handle solve the problem.
-
supercat about 13 years@Xaqron: If the class were properly designed, its Cancel method would simply do nothing if it has already been disposed (if it couldn't always avoid doing something that might cause an exception, it should stifle the exception within itself).
-
Vladyslav Tsvek about 5 years
CancellationTokenSource
can't be inherited. It is a sealed class -
Dominic Jonas over 3 yearsIt's not
sealed
. See referencesource.microsoft.com/#mscorlib/system/threading/… -
Felix K. over 2 yearsIn general i agree but there are scenarios where this would lead to a lot additional code, cancelling should be possible without causing a exception. I currently work on a application where i either use a different mechanism to cancel tasks ( Which would be bad as part of it might become a public API ) or using the workaround to catch said exceptions.
-
Kim Homann about 2 yearsIt was a sealed class in .NET Framework 4.0, but not anymore in .NET Framework 4.5+