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

我已经开始使用实现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(string name, T value) { _xwriter.WriteStartAttribute(name); _xwriter.WriteValue(value); _xwriter.WriteEndAttribute(); } public void WriteValue(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 } } 

导致:

      

我看到的主要缺点(除了非标准使用using语句可能违反了“最小意外原则”),它将尝试在XmlWriter抛出exception的情况下重复编写所有嵌套的结束标记。

至少在理论上,您可以在编写内部结束标记时抛出exception,然后在using语句生成的“finally”块中成功写入外部结束标记。 这会导致输出无效。

这有什么不好的方面,

不管怎么说,应该避免使用析构函数(终结函数),即使是有资源的类通常也可以(更好)没有。

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

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

这些IDisposable不会实现Microsoft推荐的复杂模式

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

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

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

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

在最坏的情况下,当终结器调用Dispose()时,XmlWriter可能已经处理掉了,你得到了一个exception。 所以没有终结者更好。