Rzućmy okiem na niesławnej IDisposable interfejsu:Dlaczego IDisposable realizacja zaprojektowany tak jest
[ComVisible(true)]
public interface IDisposable
{
void Dispose();
}
i typowej implementacji, zgodnie z zaleceniem MSDN (I pominięta sprawdzanie, czy obecny obiekt został już umieszczony):
public class Base : IDisposable
{
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// release managed
}
// release unmanaged
disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Base()
{
Dispose(false);
}
}
public class Derived : Base
{
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
// release managed
}
// release unmanaged
disposed = true;
}
}
Problem jest następujący: Myślę, że ta implementacja jest sprzeczna z intuicją. Jest również znacząco różny w klasie podstawowej i pochodnej. Klasa pochodna ma na celu założyć, że klasa podstawowa zaimplementowana prawidłowo IDisposable, a następnie przesłonić Dispose (bool), która nie jest nawet częścią oryginalnego interfejsu.
Muszę przyznać, że wpadłem na to pytanie, ponieważ zwykle prosiłem młodszych programistów o wdrożenie IDisposable na rozmowę o pracę. Jeśli nie wiem dokładnie, jak to ma być zrobione, oni wymyślić coś blisko tego:
public class Base : IDisposable
{
public virtual void Dispose()
{
// release managed and unmanaged
GC.SuppressFinalize(this);
}
~Base()
{
// release unmanaged
}
}
public class Derived : Base
{
public override void Dispose()
{
// release managed and unmanaged
base.Dispose();
}
~Derived()
{
// release unmanaged
}
}
do mnie, to realizacja jest bardziej jasne i bardziej spójne. Oczywiście, złe jest to, że musimy wydać niezarządzane zasoby w dwóch różnych miejscach, ale ważne jest to, że prawdopodobnie ponad 99% klas niestandardowych nie ma niczego niezarządzanego do usunięcia, więc i tak nie będą potrzebować finalizatora. Nie umiem wytłumaczyć młodszemu programistowi, dlaczego implementacja MSDN jest lepsza, ponieważ sam tego nie rozumiem.
Zastanawiam się więc, co doprowadziło do tak niezwykłych decyzji projektowych (uczynienie klasy pochodnej nadrzędną inną metodą niż w interfejsie i zmuszanie go do myślenia o niezarządzanych zasobach, których najprawdopodobniej nie zawiera). Wszelkie przemyślenia w tej sprawie?
Nieprawidłowy. Jeśli dysponujesz zasobami, powinieneś wdrożyć IDisposable i zutylizować je. – SLaks
Nie zawsze prawda. Być może typem enkapsulacji jest natywne zasoby lub implementacja typu faktorowego. –
@SLaks: Jeśli zasoby są w pełni zarządzane, jest to mniej ważne (ponieważ całkowicie zarządzany typ będzie obsługiwany poprawnie przez GC ...) –