2012-03-01 10 views
7

Zacząłem używać klas implementujących IDisposable do pisania bloków w strumieniach, za pomocą instrukcji using. Jest to pomocne w utrzymywaniu prawidłowego zagnieżdżania i unikaniu brakujących lub nieprawidłowo umieszczonych części początkowych/końcowych.using (IDisposable obj = new ...) w C# do pisania bloków kodu w strumieniu (np. XML)

Zasadniczo konstruktor zapisuje początek bloku (np. Otwierając znacznik XML), Usuwa() koniec (np. Zamykający znacznik XML). Przykładem jest plik UsableXmlElement poniżej (dotyczy to dużych plików XML, więc LINQ do XML lub XmlDocument w pamięci nie są opcjami).

Jednak te IDisposable nie implementują wyrafinowanego wzorca zalecanego przez Microsoft, z Destructor/Finalizer, oddzielną metodą Dispose (bool) i GC.SuppressFinalize(). Dispose po prostu pisze element końcowy i to wszystko.

Czy jest jakiś problem z tym związany, czy jest to dobry sposób na utrzymanie prawidłowego zagnieżdżenia elementów?

class UsableXmlElement : IDisposable 
{ 
    private XmlWriter _xwriter; 

    public UsableXmlElement(string name, XmlWriter xmlWriter) 
    { 
     _xwriter = xmlWriter; 
     _xwriter.WriteStartElement(name); 
    } 

    public void WriteAttribute<T>(string name, T value) 
    { 
     _xwriter.WriteStartAttribute(name); 
     _xwriter.WriteValue(value); 
     _xwriter.WriteEndAttribute(); 
    } 

    public void WriteValue<T>(T value) 
    { 
     _xwriter.WriteValue(value); 
    } 

    public void Dispose() 
    { 
     _xwriter.WriteEndElement(); 
    } 
} 

Wykorzystanie jest tak:

var xWriter = new XmlWriter(...) 

using(var rootElement = new UsableXmlElement("RootElement", xWriter) 
{ 
    rootElement.WriteAttribute("DocVersion", 123) 
    using(var innerElement = new UsableXmlElement("InnerElement", xwriter) 
    { 
     // write anything inside Inner element 
    } 
} 

Wynikające w:

<RootElement DocVersion="123"> 
    <InnerElement> 
     <!-- anything --> 
    </InnerElement> 
</RootElement> 
+2

Dlaczego powinien to być problem? Nie zdobędziesz żadnych niezarządzanych zasobów w pliku UsableXmlElement, więc nie potrzebujesz żadnych finalizatorów, myślę, że ... – user1096188

+0

Aha, i nie potrzebujesz parametrów WriteValue i WriteAttribute, aby były ogólne. Nic nie robi, ponieważ parametr _xwriter.WriteValue zawsze będzie wywoływany z parametrem obiektu. – user1096188

+0

Hummmmmm ........ – code4life

Odpowiedz

2

Czy istnieje Wadą tego

nr destruktory (finalizatorów) należy unikać czegokolwiek ay, nawet klasa z zasobami może zwykle zrobić (lepiej) bez.

czy jest to dobry sposób na utrzymanie prawidłowego zagnieżdżenia elementów?

Tak. Jako odniesienia można użyć System.Web.Mvc.Html.MvcForm.

te nie IDisposable wdrożenia zaawansowanego zalecaną przez Microsoft

wzór, który 'full' wzór jest poprawny, ale stary. Opisuje tylko sytuację dla "gołego" niezarządzanego zasobu. Oficjalne referencje dotyczące wyłącznie zarządzania zasobami nie są dostępne, na szczęście.

3

Główną wadą, jaką widzę (oprócz niestandardowego użycia oświadczenia za pomocą, które prawdopodobnie narusza "zasadę najmniejszej niespodzianki") jest to, że będzie próbował wielokrotnie pisać wszystkie zagnieżdżone znaczniki końcowe w przypadku wyjątku wyrzucony przez twój XmlWriter.

Przynajmniej teoretycznie można napisać wyjątek podczas pisania wewnętrznego znacznika końcowego, a następnie udane zapisywanie zewnętrznych znaczników końcowych w blokach "końcowych" generowanych przez instrukcje użycia. Doprowadziłoby to do nieprawidłowych wyników.

+0

Nigdy nie słyszałem o nim, określanym jako "zasada najmniejszej niespodzianki". Będę używał tego wyrażenia w przyszłości :) –

1

Złożony wzór używany przez Microsoft jest tworzony w celu zapewnienia uwolnienia zasobów niezarządzanych, nawet jeśli użytkownik nie zadzwoni pod numer Dispose().

Nie używasz żadnych zasobów niezarządzanych w swoich klasach. Po prostu skorzystaj ze słowa kluczowego w języku C#, aby uczynić twój kod czytelniejszym i łatwiejszym w utrzymaniu. Myślę, że to miłe podejście i używałem go również w przeszłości.

Myślę, że nie byłoby sensu używać konstrukcji finalizatora, ponieważ musisz mieć pewność, że tag końcowy zostanie zapisany we właściwym miejscu. Nigdy nie wiadomo, kiedy wywoływany jest finalizator, więc nie można mieć pewności, kiedy tag końcowy zostanie zapisany, jeśli zapomni się wyrzucić element. Twój dokument Xml nadal będzie pomieszany, niezależnie od tego, czy tag końcowy nie jest zapisany w ogóle, czy w niewłaściwej pozycji.

W najgorszym przypadku, gdy finalizator wywoła Dispose(), XmlWriter może być już usunięty i pojawi się wyjątek. Więc lepiej nie finalizatora.

Powiązane problemy