C# 如何找出已处理的对象?

C# 如何找出已处理的对象?,c#,dispose,cancellationtokensource,C#,Dispose,Cancellationtokensource,我有一个多线程应用程序,一个CancellationToken用作共享对象。每个线程都可以触发它,告诉其他线程作业已取消。然后一个线程进行清理,并像这样处理每个对象CancellationToken。然后,如果线程尝试使用它,则会引发异常: CancellationTokenSource已被释放 if (!object.IsDisposed) object.DoSomething(); 如何在使用对象之前发现它已被处置?根据Reflector的说法,CancellationTokenSourc

我有一个多线程应用程序,一个
CancellationToken
用作共享对象。每个线程都可以触发它,告诉其他线程作业已取消。然后一个线程进行清理,并像这样处理每个对象
CancellationToken
。然后,如果线程尝试使用它,则会引发异常:

CancellationTokenSource已被释放

if (!object.IsDisposed) object.DoSomething();

如何在使用对象之前发现它已被处置?

根据Reflector的说法,
CancellationTokenSource
有一个内部
IsDisposed
方法,该方法本可以告诉您,但由于它是内部的,所以您不应该调用它

在任何情况下,如果一个线程拉出其他线程依赖的数据结构和对象,那么就不要这样做。修复您的代码,并让这些对象在其需要期间保持活动状态


换句话说,等待其他线程完成所需的
CancellationTokenSource
,然后再处理它。

在使用对象之前检查对象是否已被处理

仍然不是最好的设计模式。然而,这里是我用来确定一个对象是否被处置的方法

if (!object.IsDisposed) object.DoSomething();


如果这不起作用,您可以尝试添加IsDisposed标志并重写dispose方法。在您自己的代码中将其设置为true。

正确的做法是,一些一次性对象的创建者稍微违反Microsoft的“规则”,即对已处置对象执行任何操作都会引发异常,相反,请遵循更一般的规则,即当方法的post条件不能满足时,应随时抛出异常。如果Cancel方法的目的是确保没有人会继续将某个作业视为活动的,甚至在调用Cancel方法之前,所有人都会将该作业视为已死亡,则无论是否处置该对象,该方法的post条件都会得到满足

if (!object.IsDisposed) object.DoSomething();
通常,设计良好的对象之外的代码不需要查询它是否已被释放,除非可能断言它已被释放。相反,对象本身应该提供方法,这些方法在已处理对象上的含义将是明确的。这些方法可能在内部使用IsDisposed标志,但必须使用防止竞争条件所需的任何锁定。一般来说,模式

if (!myThing.isDisposed) myThing.DoSomething(); 如果(!myThing.isDisposed) 虚构的,虚构的;
表示虚构应该真正支持DoSomethingIfNotDisposed方法(可能称为TryDoSomething)。如果您不能做到这一点,我可能会编写您自己的doSomethingNotDisposed扩展方法,并使用Try/Catch阻止ObjectDisposedException(或对象将抛出的任何特定异常)。

继承您的类并添加属性:

class MyCancellationTokenSource: CancellationTokenSource
{
    public bool MyIsDisposed { get; private set; }
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        MyIsDisposed = true;
     }
}

为什么一个线程仍在使用清理资源?对我来说,这似乎是一个很大的设计缺陷。
CancellationToken
用于同步。当两个线程试图同时取消作业时,就会发生这种情况。也许锁定它会有帮助?请修复您的问题顺便说一句,您没有处理
取消令牌
,这是无法完成的。您正在使用
CancellationTokenSource
。那么使用一个如何?(虽然我同意@lassee,但似乎实现是错误的。我有一个,但问题是竞争条件。可能是等待句柄解决了问题。@Xaqron:如果类设计正确,如果它已经被释放,它的Cancel方法将什么也不做。)(如果它不能总是避免做一些可能导致异常的事情,它应该抑制自身的异常)。
CancellationTokenSource
无法继承。它是一个密封的类,而不是
密封的
。请参阅