Как проверить, был ли объект расположен в C # [duplicate]

68
задан Community 23 May 2017 в 10:31
поделиться

4 ответа

Хорошим способом является производная от TcpClient и переопределение метода Disposing(bool):

class MyClient : TcpClient {
    public bool IsDead { get; set; }
    protected override void Dispose(bool disposing) {
        IsDead = true;
        base.Dispose(disposing);
    }
}

Что не сработает, если другой код создал экземпляр. Тогда вам придется сделать что-то отчаянное, например, использовать Reflection для получения значения приватного члена m_CleanedUp. Или поймать исключение.

Честно говоря, все это, скорее всего, не приведет к хорошему результату. Вы действительно хотели писать в TCP-порт. Но вы этого не сделаете, этот глючный код, который вы не можете контролировать, теперь контролирует ваш код. Вы увеличили влияние ошибки. Поговорить с владельцем этого кода и что-нибудь придумать - это, безусловно, лучшее решение.

EDIT: Пример отражения:

using System.Reflection;
public static bool SocketIsDisposed(Socket s)
{
   BindingFlags bfIsDisposed = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty;
   // Retrieve a FieldInfo instance corresponding to the field
   PropertyInfo field = s.GetType().GetProperty("CleanedUp", bfIsDisposed);
   // Retrieve the value of the field, and cast as necessary
   return (bool)field.GetValue(s, null);
}
32
ответ дан 24 November 2019 в 14:21
поделиться

Надежное решение - ловить ObjectDisposedException.

Решение написать свою переопределенную реализацию метода Dispose не работает, так как существует состояние гонки между потоком, вызывающим метод Dispose, и потоком, обращающимся к объекту: после проверки гипотетического свойства IsDisposed объект может быть действительно утилизирован, выбросив при этом исключение.

Другим подходом может быть экспонирование гипотетического события Disposed (как this), которое используется для уведомления об утилизации объекта каждому заинтересованному объекту, но это может быть трудно спланировать в зависимости от дизайна программного обеспечения.

30
ответ дан 24 November 2019 в 14:21
поделиться

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

Типичный шаблон для Dispose, согласно Microsoft:

public void Dispose() 
{
    Dispose(true);

    // Use SupressFinalize in case a subclass
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);      
}

protected virtual void Dispose(bool disposing)
{
    // If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    if (!_disposed)
    {
        if (disposing) {
            if (_resource != null)
                _resource.Dispose();
                Console.WriteLine("Object disposed.");
        }

        // Indicate that the instance has been disposed.
        _resource = null;
        _disposed = true;   
    }
}

Обратите внимание на проверку _disposed. Если бы вы вызвали метод Dispose, реализующий этот паттерн, вы могли бы вызывать Dispose сколько угодно раз, не сталкиваясь с исключениями.

16
ответ дан 24 November 2019 в 14:21
поделиться

Лучшая практика говорит о том, чтобы реализовать это самостоятельно, используя локальное поле boolean: http://www.niedermann.dk/2009/06/18/BestPracticeDisposePatternC.aspx

0
ответ дан 24 November 2019 в 14:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: