Как вы "правильно" реализуете Dispose() (согласно FxCop), когда ваша реализация является пустым методом? (CA1063)

У меня есть реализация интерфейса, и этот интерфейс расширяется IDisposable, В моей конкретной реализации интерфейса мне не нужно ничего утилизировать, поэтому у меня просто пустое Dispose() метод.

public interface IMyStuff : IDisposable
{
}

public MyStuffImpl : IMyStuff
{
    public void Dispose()
    {
    }
}

Теперь в FxCop это приводит к CA1063:

Error, Certainty 95, for ImplementIDisposableCorrectly
{
    Resolution   : "Provide an overridable implementation of Dispose(
                   bool) on 'MyStuffImpl' or mark the type as sealed. 
                   A call to Dispose(false) should only clean up native 
                   resources. A call to Dispose(true) should clean up 
                   both managed and native resources."
}
CriticalWarning, Certainty 75, for CallGCSuppressFinalizeCorrectly
{
    Resolution   : "Change 'MyStuffImpl.Dispose()' to call 'GC.SuppressFinalize(
                   object)'. This will prevent derived types that introduce 
                   a finalizer from needing to re-implement 'IDisposable' 
                   to call it."
}
Error, Certainty 95, for ImplementIDisposableCorrectly
{
    Resolution   : "Modify 'MyStuffImpl.Dispose()' so that it 
                   calls Dispose(true), then calls GC.SuppressFinalize 
                   on the current object instance ('this' or 'Me' in Visual 
                   Basic), and then returns."
}

Итак, похоже, что я могу решить это одним из двух способов:


Сделать класс sealed:

public sealed MyStuffImpl : IMyStuff
{
    public void Dispose()
    {
    }
}

Реализуйте часть типового шаблона:

public MyStuffImpl : IMyStuff
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
    }
}

В моем случае я не планирую расширять эту реализацию, поэтому я, вероятно, разрешу ее, сделав ее sealed, но я признаю, что я действительно не понимаю, почему это важно, если оно запечатано или нет.

Кроме того, только потому, что мой класс запечатан, FxCop больше не говорит мне, что Dispose() должен позвонить GC.SupressFinalize(this); но так ли это на самом деле? Является ли "лучше" в.NET, чтобы всегда вызывать SupressFinalize в Dispose независимо?

2 ответа

Решение

SuppressFinalize() не имеет смысла, если у вашего экземпляра нет финализатора.
Если в вашем классе нет финализатора, но его нет sealed, ты должен еще SuppressFinalizeВ случае, если унаследованный класс добавляет финализатор.

Оба ваших варианта верны, за исключением того, что Dispose(bool) должно быть protected virtual,

В вашей опции "реализовать часть типичного шаблона" вы должны сделать Dispose(bool) метод protected virtual:

protected virtual void Dispose(bool disposing) 
{ 
} 

Это даст подклассам возможность распоряжаться любыми ресурсами, которыми они управляют. Это означает "переопределяемый" в "Обеспечить переопределяемую реализацию Dispose (bool)"

Конечно, public virtual также удовлетворит FxCop.

Другие вопросы по тегам