Как вы "правильно" реализуете 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 независимо?

Ответ 1

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

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

Ответ 2

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

protected virtual void Dispose(bool disposing) 
{ 
} 

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

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