在C#中使用(IDisposable obj = new ...)来编写流中的代码块(例如XML)

时间:2012-03-01 11:38:45

标签: c# xml stream idisposable using-statement

我已经开始使用实现IDisposable的类来使用using语句在流中写入块。这有助于保持正确的嵌套并避免丢失或错误放置起始/终止部件。

基本上,构造函数写入块的开头(例如打开XML标记),Dispose()结束(例如关闭XML标记)。示例是下面的UsableXmlElement(它适用于大型XML,因此内存中的LINQ to XML或XmlDocument不是选项)。

但是,这些IDisposable并未实现Microsoft推荐的复杂模式,使用Destructor / Finalizer,单独的Dispose(bool)方法和GC.SuppressFinalize()。 Dispose只是简单地写出end元素,就是这样。

是否存在任何不利因素,或者这是保持元素正确嵌套的好方法?

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();
    }
}

用法是这样的:

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
   }
}

导致:

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

3 个答案:

答案 0 :(得分:3)

我看到的主要缺点(除了非标准使用using语句可能违反&#34;最少意外的原则&#34;)是它会尝试重复写入所有嵌套的结束标记您XmlWriter抛出的异常事件。

至少在理论上,你可以在编写内部结束标记时抛出异常,然后在&#34;最后&#34;中成功写入外部结束标记。 using语句生成的块。这会导致输出无效。

答案 1 :(得分:2)

  

这是否有任何不利因素,

没有。无论如何都应该避免使用析构函数(终结函数),即使是拥有资源的类通常也可以(更好)没有。

  

或者这是保持元素正确嵌套的好方法吗?

是。您可以使用System.Web.Mvc.Html.MvcForm作为参考。

  

这些IDisposable没有实现Microsoft推荐的复杂模式

这种'完整'模式是正确但过时的。它仅描述了“裸”非托管资源的情况。不幸的是,没有提供仅用于处理托管资源的官方参考。

答案 2 :(得分:1)

创建microsoft使用的复杂模式是为了确保释放非托管资源,即使您没有调用Dispose()

您不在类中使用任何非托管资源。您只需利用C#的using关键字来使您的代码更具可读性和可维护性。我认为这是一个很好的方法,我也曾在过去使用它。

我认为使用终结器构造甚至没有意义,因为您需要确保结束标记写在正确的位置。您永远不知道何时调用终结器,因此如果您忘记处理元素,则无法确定何时会写入结束标记。无论结束标记是完全写入还是错误位置,您的Xml文档仍然会混乱。

在最坏的情况下,当终结器调用Dispose()时,XmlWriter可能已被释放,并且您将获得异常。所以最好没有终结者。