Как узнать, что объект утилизировал?


У меня есть многопоточное приложение, и CancellationToken используется в качестве общего объекта. Каждый поток может вызвать его, чтобы сообщить другим потокам, что задание отменено. Затем один поток выполняет очистку и распределяет каждый объект следующим образом CancellationToken. Затем, если поток пытается использовать его, возникает исключение:

CancellationTokenSource был удален.

Как я могу узнать, что объект расположен, прежде чем использовать его?

4 6

4 ответа:

Ну, согласно Reflector, CancellationTokenSource имеет внутренний метод IsDisposed, который мог бы вам сказать, но поскольку он внутренний, вы не должны его вызывать.

В любом случае, если один поток выдергивает структуры данных и объекты, от которых зависят другие потоки, то не делайте этого. Исправьте свой код и оставьте эти объекты жить на время их потребности.

Другими словами, дождитесь, пока другие потоки закончат нуждаться в CancellationTokenSource, прежде чем избавиться от него.

Правильнее было бы для создателей некоторых одноразовых объектов пойти немного против "правила" Microsoft, что выполнение любого действия над удаленным объектом должно вызвать исключение, и вместо этого следовать более общему правилу, что исключение должно быть вызвано в любое время, когда постусловия метода не могут быть выполнены. Если цель метода отмены состоит в том, чтобы гарантировать, что никто не будет продолжать рассматривать работу как живую, и даже до того, как метод отмены будет вызван, все считают задание как мертвое, то постусловие для метода выполняется независимо от того, удален ли объект.

Как правило, код вне хорошо спроектированного объекта не должен запрашивать, был ли он удален, за исключением, возможно, утверждения, что он был удален. Вместо этого сам объект должен предоставлять методы, значение которых для удаленного объекта было бы ясным и недвусмысленным. Эти методы могли бы внутренне использовать флаг IsDisposed, но должны были бы использовать любую блокировку необходимо предотвратить условия гонки. В общем, паттерн

  if (!myThing.isDisposed) 
    myThing.DoSomething();

- это указание на то, что myThing действительно должен поддерживать метод DoSomethingIfNotDisposed (возможно, называемый TryDoSomething). Если вы не можете этого сделать, я склоняюсь к тому, чтобы написать свой собственный метод расширения DoSomethingIfNotDisposed и использовать Try/Catch, чтобы подавить исключение ObjectDisposedException (или любое другое конкретное исключение, которое вызовет объект).

Перед использованием объекта убедитесь, что он удален.

Все еще не лучший шаблон дизайна. однако вот то, что я использую, действительно определяет, расположен ли объект.

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

Или

public string DoSomething()
{
    if (this.IsDisposed) return null;
}

Если это не работает, вы можете попробовать добавить флаг IsDisposed и переопределить метод dispose. И установите это значение true в своем собственном коде.

Унаследуйте свой класс и добавьте свойство:

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