Ich habe eine abstrakte Klasse, die IDisposable wie folgt implementiert:
%Vor%In Visual Studio 2008 Team System habe ich Code Analysis für mein Projekt ausgeführt und eine der folgenden Warnungen war die folgende:
Microsoft.Design: Ändern Sie "ConnectionAccessor.Dispose ()" so, dass es Dispose (true) aufruft, und ruft dann GC.SuppressFinalize für die aktuelle Objektinstanz ("this" oder "Me" in Visual Basic) auf und kehrt dann zurück .
Ist es nur albern, mir zu sagen, dass ich den Körper einer abstrakten Methode modifizieren soll, oder sollte ich etwas in einer abgeleiteten Instanz von Dispose
machen?
Sie sollten dem herkömmlichen Muster für die Implementierung von Dispose
folgen. Das Erstellen von Dispose()
virtual wird als schlechte Methode betrachtet, da das herkömmliche Muster die Wiederverwendung von Code in "managed cleanup" (API-Client ruft Dispose()
direkt oder via using
) und "nicht verwaltete Bereinigung" (GC-Aufruffinalisierer) hervorhebt. Zur Erinnerung, das Muster ist das:
Der Schlüssel hier ist, dass es keine Verdoppelung zwischen dem Finalizer und Dispose
für die nicht verwaltete Bereinigung gibt und dass jede abgeleitete Klasse sowohl die verwaltete als auch die nicht verwaltete Bereinigung erweitern kann.
Für Ihren Fall sollten Sie Folgendes tun:
%Vor% und lass alles andere so wie es ist. Auch das ist von zweifelhaftem Wert, da Sie Ihre abgeleiteten Klassen dazu zwingen, jetzt Dispose
zu implementieren - und woher wissen Sie, dass sie alle brauchen? Wenn Ihre Basisklasse nichts zu erledigen hat, aber die meisten abgeleiteten Klassen wahrscheinlich (mit einigen Ausnahmen, vielleicht), dann geben Sie einfach eine leere Implementierung an. Es ist was System.IO.Stream
(selbst abstrakt) tut, also gibt es Präzedenzfälle.
Die Warnung weist Sie im Wesentlichen an, das Dispose-Muster zu implementieren in deiner Klasse.
Der resultierende Code sollte wie folgt aussehen:
%Vor% Das einzige Problem, das ich mit den bisher gelieferten Antworten haben könnte, ist, dass alle davon ausgehen, dass Sie
Siehe diesen Blogbeitrag von Joe Duffy, der erklärt, wann Sie einen Finalizer benötigen oder nicht, und wie Sie das Dispose-Pattern in jedem Fall richtig implementieren können.
Wenn Sie Joes Blogpost zusammenfassen, sollten Sie keinen Finalizer implementieren, es sei denn, Sie tun etwas, das mit nicht verwaltetem Speicher zu tun hat. Als allgemeine Faustregel gilt, dass wenn Ihre Klasse nur Verweise auf verwaltete Typen enthält, die IDisposable selbst implementieren, Sie den Finalizer nicht benötigen (aber IDisposable implementieren und diese Ressourcen entfernen sollten). Wenn Sie nicht verwaltete Ressourcen direkt aus Ihrem Code (PInvoke?) Zuweisen und diese Ressourcen freigegeben werden müssen, benötigen Sie eine. Eine abgeleitete Klasse kann immer einen Finalizer hinzufügen, wenn sie dies wirklich benötigt, aber wenn alle abgeleiteten Klassen durch Einfügen in die Basisklasse einen Finalizer erhalten, werden alle abgeleiteten Klassen vom Leistungstreffer der finalisierbaren Objekte beeinflusst, wenn dieser Overhead nicht vorhanden ist notwendig.
Obwohl es ein wenig wie Nit-Picking scheint, ist der Ratschlag gültig. Sie geben bereits an, dass Sie erwarten, dass Untertypen von ConnectionAccessor etwas haben, das sie entsorgen müssen. Daher scheint es besser zu sein, sicherzustellen, dass die richtige Bereinigung (in Bezug auf den GC.SuppressFinalize-Aufruf) von der Basisklasse durchgeführt wird, anstatt sich auf jeden Untertyp zu verlassen.
Ich verwende das in Bruce Wagners Buch Effective C # genannte Entsorgungsmuster, das im Grunde Folgendes ist:
%Vor%Die Warnung ist jedoch interessant. Eric Lippert, einer der C # -Designer, bloggte darüber, warum Fehlermeldungen "Diagnostisch, aber nicht präskriptiv sein sollten: Beschreibe das Problem, nicht die Lösung". Lesen Sie hier.
Tags und Links c# abstract-class static-analysis dispose