Пользовательские функции инициализации с IDisposable - PullRequest
0 голосов
/ 11 сентября 2011

В .NET (C #) я следую некоторым пользовательским соглашениям и шаблонам, которые требуют Конструкторов, функций инициализации и IDisposable реализаций.Типичный класс показан ниже.Инициализация не выполняется непосредственно в конструкторе, а осуществляется через специальную функцию, которая должна сделать объект повторно используемым.Тем не менее, я не уверен, что происходит, когда вызывается Dispose.Если GC вызывает его, ссылка на объект в любом случае теряется, поэтому не стоит беспокоиться.Если он вызывается явно, есть ли какие-либо недостатки, просто вызывающие Initialize и обрабатывающие класс как новый объект, так как был вызван GC.SupressFinalize?Лол, я уверен, что мог бы спросить об этом проще.

public abstract class Thread: System.IDisposable
{

    protected bool Disposed { get; set; }
    protected bool Terminate { get; private set; }
    public bool IsRunning { get; private set; }
    private System.Threading.Thread ThreadObject { get; set; }

    public Thread ()
    {
        this.Initialize();
    }

    ~Thread ()
    {
        this.Dispose(false);
    }

    public virtual void Initialize ()
    {
        this.Stop();

        this.Disposed = false;
        this.Terminate = true;
        this.IsRunning = false;
        this.ThreadObject = null;
    }

    //====================================================================================================
    // Functions: Thread
    //====================================================================================================

    public void Start ()
    {
        if (!this.IsRunning)
        {
            this.IsRunning = true;
            this.Terminate = false;

            this.ThreadObject = new System.Threading.Thread(new System.Threading.ThreadStart(this.Process));
            this.ThreadObject.Start();
        }
    }

    /// <summary>
    /// Override this method to do thread processing.
    /// [this.Terminate] will be set to indicate that Stop has been called.
    /// </summary>
    /// <param name="template"></param>
    protected abstract void Process ();

    public void Stop (System.TimeSpan timeout)
    {
        if (this.IsRunning)
        {
            this.Terminate = true;

            try
            {
                if (timeout.TotalMilliseconds > 1D)
                {
                    this.ThreadObject.Join(timeout);
                }
                else
                {
                    this.ThreadObject.Join();
                }
            }
            catch
            {
                try
                {
                    this.ThreadObject.Abort();
                }
                catch
                {
                }
            }

            this.ThreadObject = null;
            this.IsRunning = false;
        }
    }

    //====================================================================================================
    // Interface Implementation: System.IDisposable
    //====================================================================================================

    public void Dispose ()
    {
        this.Dispose(true);

        System.GC.SuppressFinalize(this);
    }

    protected virtual void Dispose (bool disposing)
    {
        if (!this.Disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                this.Stop(System.TimeSpan.FromSeconds(1));
            }

            // Dispose unmanaged resources here.

            // Note disposing has been done.
            this.Disposed = true;
        }
    }

}

Ответы [ 4 ]

1 голос
/ 11 сентября 2011

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

Если вы действительно хотите пойти по этому пути, я бы избегал использования финализатора, что означает, что ваш IDisposable класс не должен напрямую владеть какими-либо неуправляемыми ресурсами. Это можно сделать, обернув любые неуправляемые ресурсы, используемые вашим классом, в управляемую оболочку (например, посмотрите на класс SafeHandle).

1 голос
/ 11 сентября 2011

GC никогда не вызывает Dispose, это зависит от потребляющего кода. Однако GC вызывает финализатор. Это используется в наилучшей реализации IDisposable для очистки только неуправляемого кода.

Если Dispose используется вне контекста финализатора, тогда GC не нужно вызывать финализатор, и поэтому SuppressFinalize используется в качестве оптимизации, чтобы предотвратить его повторение дважды.

Если объект используется повторно, это вызывает проблему. Технически вы можете перерегистрировать финализатор при инициализации, но это необходимо сделать поточно-ориентированным. Обычная практика заключается в том, что объект не используется повторно после того, как он был Disposed, и обычно метод Dispose должен выполняться только один раз. IMO метод инициализатора и повторное использование объекта вносит сложности в шаблон, которые перемещают его от его предназначения.

0 голосов
/ 11 сентября 2011

В коде используется неверный образец приложения языкового шаблона. Я ясно вижу C ++ backgroung для автора кода C #. К сожалению, методы кодирования C ++ не применимы на языке C #.

Лучше не допускать попадания объекта в сборщик мусора (GC), просто ссылаясь на него где-то еще, как в шаблоне Singleton, вместо того, чтобы пытаться воскресить удаленный объект, или использовать шаблон Dispose на языке, не обеспечивающем полный контроль над сборщик мусора и управление памятью, как и должно быть, например, в C ++.

Проще говоря, вы не должны использовать идиомы C ++ в C #, но советы и хитрости:

Интерфейсы вместо чисто виртуальных функций в C ++, Наследование интерфейса вместо наследования нескольких классов в C ++, Нет управления памятью (используйте слабые ссылки) вместо полного времени жизни контролируемого объекта в C ++

0 голосов
/ 11 сентября 2011

Мне не нравятся все точные детали обработки вашего потока, но если у вас будет класс, в котором каждый экземпляр владеет потоком, вы должны предоставить метод Dispose, который гарантирует, что поток экземпляра отмирает вупорядоченный способ.

Если вы хотите разрешить очистку потока, даже если объект оставлен, вам, вероятно, придется создать объект-оболочку, на которую ссылается внешнее приложение, а ваш поток -не.Метод Finalize () для этого объекта-обертки должен подтолкнуть поток таким образом, что он умрет.Поток может просто опрашивать флаг каждые несколько секунд, чтобы определить, должен ли он выйти, или может существовать более изощренная стратегия завершения.

Однако я запутался, почему Initialize вызывает Stop ()?Я ожидал бы, что это вызовет Start ().

...