2015-08-26 8 views
5

An einigen Stellen haben Leute vorgeschlagen, private void Dispose(bool) für das Muster IDisposable zu verwenden. Dies scheint jedoch (zumindest für nicht versiegelte Klassen) veraltet zu sein, da das neue vorgeschlagene Muster (nach Microsoft) protected virtual void Dispose(bool) ist.private void Dispose (bool)?

Die Sache ist, Code-Analyse berichtet nicht private void Dispose(bool) für Verletzung CA1063, obwohl es scheint, das Muster direkt zu verletzen.

Was ist los? ? Ist private void Dispose(bool) irgendwie immer genannt (oder etwas zusammengestellt, wie protected virtual Dispose(bool) sieht

Wenn dies einig Problem mit dem Code-Analyse und ist das falsche Muster, gibt es Möglichkeiten, dies zu erkennen, möglicherweise mit StyleCop

bearbeiten?: nach Prüfung ist es, dass eine Basisklasse base.Dispose() nennen kann, welche private void Dispose(bool) getroffen, auch wenn es nicht in der Lage ist, in einem Argument übergeben

Edit:? Beispiel

public class A : IDisposable 
{ 
    ~A() 
    { 
     this.Dispose(false); 
    } 

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

    private void Dispose(bool disposing) // Should be protected virtual void Dispose(bool) 
    { 
     Console.WriteLine("A"); 
    } 
} 

public class B : A 
{ 
    protected virtual void Dispose(bool disposing) // Proper pattern. 
    { 
     Console.WriteLine("B"); 
    } 
} 

public static class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(); 
     a.Dispose(); // Prints "A" 

     B b = new B(); 
     b.Dispose(); // Prints "A"! 
    } 
} 

Wie Sie sehen können, macht es die Verwendung des Entsorgungsmusters völlig unhandlich.

Sie können dies ein wenig umgehen, indem Sie die public void Dispose(void) verstecken und dann base.Dispose() irgendwo anrufen. Dies funktioniert dann "ähnlich" wie das richtige Entsorgungsmuster beim Aufruf B b = new B(); b.dispose();mit Ausnahme von beim Aufruf A b = new B(); b.Dispose();, die nur ADispose Methode 10 aufrufen.

public class B : A 
{ 
    public void Dispose() // Causes CA error with or without "new". 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) // Proper pattern. 
    { 
     base.Dispose(); // Writes "A" (without quotes). 
     Console.WriteLine("B"); 
    } 
} 

Grundsätzlich scheint diese ganze Sache schrecklich. Wissen wir, ob es ein Fehler ist, den CA akzeptiert private void Dispose(bool) und gibt es eine Möglichkeit, eine Warnung mit StyleCop zumindest zu werfen?

Edit: Ich glaube nicht, dass ich Alexandres Antwort akzeptieren sollte, denn relativ zu der Frage, die ich habe, läuft es im Grunde auf "Könnte ein Fehler sein", zusammen mit etwas, das ein Kommentar sein sollte. Wenn jemand anderes etwas Schlüssigeres hat, wäre das meiner Meinung nach eine angemessenere Antwort.

+0

Was ist mit versiegelten Klassen? Geschützt sollte für offene Klassen verwendet werden, private für versiegelte. –

+0

Es funktioniert für beide ist das Problem. Wir fanden ein paar Orte, an denen offene Klassen das Problem nicht anstellten. Das macht jedoch Sinn, dass private für versiegelte Klassen benötigt wird. Trotzdem wäre es nett, wenn CA die Klasse entsiegelt (und das sollte es auch wissen). Ich denke mein Schnitt zeigt, warum es vielleicht nicht ganz aus dem Wald ist, um es nicht zu werfen, aber es ist immer noch ein bisschen nervig. –

+0

Der Aufruf von 'base.Dispose()' wäre eine klare Verletzung des Musters, also glaube ich nicht, dass es das erklärt. Ich stimme Ihrem ursprünglichen Gedanken zu, dass Code Analysis den von Ihnen präsentierten Fall melden sollte. – sstan

Antwort

6

Implementing a Dispose Method

Die IDisposable Schnittstelle erfordert die Implementierung eines einzigen parameter Methode entsorgen. jedoch, die dispose Muster erfordernzwei Entsorgen Methoden umgesetzt werden:

  • öffentlichen nicht-virtuelle (nicht vererbbare in Visual Basic) IDisposable.Dispose Implementierung, die keine Parameter hat.
  • Eine geschützte virtuelle (Overridable in Visual Basic) Dispose-Methode.

Da die Öffentlichen, nicht-virtuellen (nicht vererbbar in Visual Basic), parameterlos Dispose-Methode durch einen Verbraucher vom Typ genannt wird, ist sein Zweck nicht verwalteten Ressourcen freizugeben und um anzuzeigen, dass der Finalizer, wenn man ist anwesend, muss nicht laufen. Aus diesem Grund ist es eine Standardimplementierung hat:

public void Dispose() 
{ 
    // Dispose of unmanaged resources. 
    Dispose (true); 
    // Suppress finalization. 
    GC.SuppressFinalize (this); 
} 

In der zweiten Überlast, die Entsorgung Parameter ist ein Boolean, ob der Aufruf der Methode (sein Wert ist true) stammt aus einer Entsorgen Methode gibt oder von a Finalizer (sein Wert ist falsch).

Wenn der Garbage Collector entscheidet, dass das Objekt nicht mehr benötigt wird, wird es versuchen, es den parameterlos dispose-Methode vergessen Sie rufen bei abzuschließen, denn wenn Sie getan haben und Sie das Muster folgen, um den Anruf würde unterdrückt werden.

See: How Finalization Works

Privat vs geschützten virtuellen:

Sie sollten immer virtuellen geschützt verwenden, wie die Dokumentation sagt, wenn Sie jemals Subklassen unterstützen wollen, die das Muster korrekt folgt.

Warum einige Leute die private Version verwenden? Vielleicht, weil Vererbung nie ihre Absicht war, besonders wenn Sie nur Methoden mit Hilfsmitteln wie Resharper erzeugen, werden diese Methoden meistens privat sein.

Warum Code-Analyse meldet das Problem nicht?

Könnte ein Fehler sein. Stellen Sie ein kleines Beispiel zur Verfügung, das das Problem aufzeigt, damit andere Personen auf ihren Computern testen können.

+0

Add ed einige Proben. –

+0

Welchen Unterschied sollte Dispose (bool) machen, wenn der Bool wahr und falsch ist? – AksharRoop

+0

Am Ende der Seite (https://msdn.microsoft.com/en-us/library/system.object.finalize.aspx) sehen Sie ein Beispiel, Wenn Sie "true", müssen Sie alle Ressourcen entsorgen, weil Sie benannte die dispose-Methode und möchte den gesamten belegten Speicher zurück haben. Wenn false, bedeutet dies, dass der Garbage Collector das Objekt löscht. Dann müssen Sie nur die nicht verwalteten Ressourcen entfernen (Objekte, die außerhalb Ihrer C# -Anwendung erstellt werden). Der Rest der Objekte kann nicht verändert werden, da der Garbage Collector gelöscht wird sie, wenn es braucht. –