Hallo!
Ich bin irritiert über die statische Codanalyse:
Ich habe eine Klasse, die ein privates Feld besitzt, das IDisposable implementiert. Die Klasse selber besitzt zurzeit keine Dispose-Methode. Wenn ich CA1001 Types that own disposable fields should be disposable richtig verstehe, sollte die statische Codeanalyse nun diese Warnung bringen, wenn ich sie laufen lasse. Tut sie aber nicht. Lt. Codeanalyse ist mein Code in Ordnung.
Verstehe ich die Regel falsch? Oder gibt es Konstellationen in denen die statische Codeanalyse den Fehler nicht erkennt?
Eine Klasse, die Methoden (hier Dispose) eines Interfaces (hier IDisposable) nicht implementieren, sind nicht kompilierbar.
Ich bezweifle also, dass der Code in Ordnung ist. 🤔 Oder hat Deine Klasse nicht mal IDisposable? Ohne Code muss man immer raten...
Und was für ein Analysetool verwendest Du denn?
Der Code aus der MSDN funktioniert mit VS 2015 Code Analyse einwandfrei. Haste das denn selbst mal als Kontrolle ausgeführt??
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Grundsätzlich sieht mein Code schon so aus, wie Deiner. Ich habe mich etwas missverständlich ausgedrückt. Natürlich hat die Klasse, die IDisposable implementiert eine Dispose Methode. Ich meinte die Klasse, die ein Feld vom Typ des IDisposables besitzt, hat keine Dispose Methode...
Warnt die Codeanalyse nur, wenn das Feld innerhalb der Klasse erstellt wurde?
Ich fürchte das Problem liegt darin, dass ich einen IoC Container (Castle Windsor) verwende, der mir das zu disposende Objekt über Constructor Injection in meine Klasse hinein reicht. Der IoC Container erstellt dabei das Objekt. Ist er evtl. so schlau das Objekt bei Zeiten auch zu disposen, sodass ich mich gar nicht darum zu kümmern brauche? Dann wäre ja tatsächlich alles in Ordnung.
Es warnt nur, wenn das Feld private ist.
Und Felder sollten immer private sein.
Wenn es also nicht innerhalb der Klasse erstellt wird, dann hast Du (offensichtlich?) kein privates Feld.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Das Feld ist private - sogar private readonly. Aber es wird aber außerhalb (vom IoC Container) erzeugt und über den Konstrukor in meine Klasse hineingereicht.
Ich hatte CA1001 so verstanden, dass die Codeanalyse (VS) immer warnt, wenn ein Feld disposable ist - unabhängig davon wer das Feld erstellt. Offensichtlich ist das nicht so. Das new ist entscheidend.
Dann muss ich mal in der Doku von Castle nachlesen, ob ich mich um das Dispose kümmern muss.
Vielen Dank, Abt für Deine Hilfe!
Dann muss ich mal in der Doku von Castle nachlesen, ob ich mich um das Dispose kümmern muss. Welchen Lifestyle hat das Objekt?
Wenn du das Objekt - auf welchem Wege auch immer - von außen mit in die Klasse reichst, dann muss sich in meiner Welt die äußere Klasse um das Dispose kümmern, da nur sie weiß, wann das Objekt nicht mehr benötigt wird.
Beispiel:
public class MeineTolleSuperKlasse
{
public MeineTolleSuperKlasse()
{
using (var stream = new FileStream(@"C:\test.txt", FileMode.Open))
{
stream.ReadByte();
//Mache irgendwas
var streamHelper = new StreamHelper(stream);
streamHelper.Reset();
stream.ReadByte();
//Mache irgendwas
}
}
}
public class StreamHelper
{
private readonly FileStream _stream;
public StreamHelper(FileStream stream)
{
_stream = stream;
}
public void Reset()
{
_stream.Position = 0;
}
}
Würde man jetzt hier erwarten, dass sich der StreamHelper um das Dispose kümmern soll?
MeineTolleSuperKlasse ist in deinem Fall der IoC-Container/Castle. =)
EDIT sagt noch, dass es auch Fälle gibt, in denen Objekte in IoC-Containern als SingleInstance erzeugt werden, er wäre katastrophal, wenn die zwischendurch einer abräumt (falls jemand nachfragt: mir ist aktuell kein praktischer Fall bekannt 😉).
Sobald etwas von Außen rein kommt, ist auch die Aussenstelle für das Disposen verantwortlich.
Die statische Codeanalyse ist in diesem Fall korrekt.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Ausnahmen von dieser Regel werden dann bei der Übergabe entsprechend vermerkt, so wie das z.B. bei StreamWriter
mit dem übergebenen Stream
erfolgt.
Bei transienten Objekten kann der Container nicht wissen wie lange du ihn brauchst. Schließlich könntest du auch mehrere Exemplare des Objektes anfordern wollen (z.B. immer wenn der Benutzer Speichern klickt willst du über das Uow Speichern, dieses verwerfen und ein neues anfordern).
Wenn die Klasse die das Objekt injiziert bekommt den Lifestyle Singleton hat wird das transiente Objekt die gesamte Zeit an diesem Singleton kleben bleiben, wird dann der Conatainer verworfen wird die Dispose-Methode aller Disposables des Containers aufgerufen. Man sollte sich überlegen ob es OK ist an ein Singleton ein Transientes Objekt zu binden.
Ansonsten ist es üblich transiente Objekte über eine Facility reinzugeben. Die hat dann eine Methode Destroy über die man das nicht mehr benötigte Objekt zurückgeben kann.