How to find out an object has disposed?
Asked Answered
L

5

10

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 this CancellationToken. 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?

Lillis answered 13/4, 2011 at 20:40 Comment(4)
Why is one thread cleaning up resources still in use? That seems like a big design flaw to me.Pavid
The CancellationToken is used for synchronization. It happens whe two threads try to cancel the job at the same time. Maybe a lock over it helps?Lillis
Please fix your question btw, you're not disposing of the CancellationToken, that can't be done. You're diposing of the CancellationTokenSource.Pavid
So how about a ManualResetEvent? (Though I'm agreeing with @lassee, seems the implementation is wrong.Nanice
P
4

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.

Pavid answered 13/4, 2011 at 20:47 Comment(1)
In 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.Stacystadholder
M
3

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).

Manpower answered 14/4, 2011 at 15:50 Comment(2)
I have one but the problem is race condition. Maybe a wait handle solve the problem.Lillis
@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).Manpower
S
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;
     }
}
Streaming answered 2/11, 2017 at 13:43 Comment(4)
CancellationTokenSource can't be inherited. It is a sealed classCorker
It's not sealed. See referencesource.microsoft.com/#mscorlib/system/threading/…Shenashenan
It was a sealed class in .NET Framework 4.0, but not anymore in .NET Framework 4.5+Sherise
Inheriting works nicely and is cleaner for disposing (or use this NuGetEnvious
O
1

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.

Orectic answered 13/4, 2011 at 20:49 Comment(0)
B
1

I agree with Lasse V. Karlsen. However, if you want it:

bool IsDisposed = true;
var privateInt = tokenSource?.GetType().GetProperty("IsDisposed", 
BindingFlags.Instance | BindingFlags.NonPublic);
if (privateInt != null)
{
   IsDisposed = (bool)privateInt.GetValue(tokenSource);
}
Bickford answered 30/5, 2022 at 7:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.