2012-01-20 18 views
10

Tengo una implementación de una interfaz, y esa interfaz se extiende a IDisposable. En mi implementación particular de la interfaz, no necesito deshacerme de nada, así que solo tengo un método Dispose() vacío.¿Cómo implementa "adecuadamente" Dispose() (según FxCop) cuando su implementación es un método vacío? (CA1063)

public interface IMyStuff : IDisposable 
{ 
} 

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

Ahora en FxCop, esto se traduce en un 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." 
} 

Por lo tanto, parece que puedo resolver esto de una de las 2 formas:


hacer que la clase sealed :

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

aplicar la parte del patrón típico:

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

    private void Dispose(bool disposing) 
    { 
    } 
} 

En mi caso, yo no pienso en esta aplicación cada vez está extendiendo, así que probablemente se resolverá por lo que es sealed, pero admito Realmente no entiendo por qué importa si está sellado o no.

Además, solo porque mi clase está sellada, FxCop ya no me dice que Dispose() debe llamar al GC.SupressFinalize(this);, pero ¿es eso cierto? ¿Es "mejor" en .NET simplemente llamar a SupressFinalize en Dispose independientemente?

+0

Quizás su interfaz no debería implementar IDisposable si tiene cosas que implementan su interfaz que no necesitan deshacerse. También puede implementar IDisposable * en su interfaz según sea necesario. –

+0

@DBM OP implementa otra interfaz que hereda IDisposable. 'IEnumerator ' es un ejemplo. – phoog

+1

@DBM: si la mayoría de las implementaciones son desechables, esta interfaz también debería ser para alentar a los usuarios de la interfaz a desechar correctamente. – SLaks

Respuesta

10

SuppressFinalize() no tiene sentido a menos que su instancia tenga un finalizador.
Si su clase no tiene un finalizador, pero no es sealed, todavía debe SuppressFinalize, en caso de que una clase heredada agregue un finalizador.

Ambas opciones son correctas, excepto que Dispose(bool) debe ser protected virtual.

+1

En realidad, la segunda opción no es correcta porque la sobrecarga 'Dispose (bool)' no es reemplazable. +1 para señalar que 'SuprimirFinalizar' no tiene sentido en objetos sin finalizador. – phoog

+0

¿Hay algún caso en el que una clase deba agregar un finalizador de limpieza a una clase base que no está diseñada para uno, y existe alguna razón por la cual dicha clase no pueda manejar GC.SuppressFinalize en su propio método Dispose? Entiendo que puede ser útil para las clases tener finalizadores cuyo propósito es simplemente registrar una falla para deshacerse de ellos, pero intentar la limpieza en un finalizador cuando la clase base no está diseñada para ello parece peligroso e incorrecto. Encapsular una instancia de una clase finalizable parecería mucho más seguro. – supercat

+0

@supercat: si la clase derivada agrega recursos no administrados. La clase derivada no puede anular 'Dispose()'. (aunque no estoy seguro de por qué no puede llamar a 'SupressFinalize()' en 'Dispose (true)') – SLaks

1

En la opción de "poner en práctica parte del patrón típico", usted debe hacer su Dispose(bool) método protected virtual:

protected virtual void Dispose(bool disposing) 
{ 
} 

que proporcionará una oportunidad subclases para manejar la eliminación de todos los recursos que administran. Ese es el significado de "invalidable" en "Proporcionar una implementación sobresatural de Dispose (bool)"

Por supuesto, public virtual también satisfaría a FxCop.

+0

Buen punto. Quizás FxCop también debería advertirme sobre eso;) – CodingWithSpike

+0

@ rally25rs Pero FxCop te advirtió sobre eso, cuando dijo "proporciona una implementación sobresatural de Dispose (bool)". ¿Desapareció la advertencia cuando proporcionó una implementación no descartable de Dispose (bool)? Si es así, eso es simplemente extraño. – phoog

+0

Sí, en mi segundo ejemplo, donde Dispose() es privado, no hay advertencia de FxCop. – CodingWithSpike

Cuestiones relacionadas