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

C# 使用C语言中的(IDisposable obj=new…)在流中编写代码块(例如XML),c#,xml,stream,idisposable,using-statement,C#,Xml,Stream,Idisposable,Using Statement,我已经开始使用实现IDisposable的类,使用using语句在流中写入块。这有助于保持正确的嵌套,避免丢失或错误放置起始/结束零件 基本上,构造函数写块的开始(例如打开XML标记),Dispose()写块的结束(例如关闭XML标记)。下面的例子是UsableXmlElement(它适用于大型XML,所以内存中的LINQ-to-XML或XmlDocument没有选项) 但是,这些IDisposable没有实现Microsoft推荐的复杂模式,包括析构函数/终结器、单独的Dispose(bool

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

基本上,构造函数写块的开始(例如打开XML标记),Dispose()写块的结束(例如关闭XML标记)。下面的例子是UsableXmlElement(它适用于大型XML,所以内存中的LINQ-to-XML或XmlDocument没有选项)

但是,这些IDisposable没有实现Microsoft推荐的复杂模式,包括析构函数/终结器、单独的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();
    }
}
导致:

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

有什么不好的地方吗

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

或者这是维护元素正确嵌套的好方法吗

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();
    }
}
对。你可以作为参考

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

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

我看到的主要缺点(除了使用using语句的非标准用法可能违反了“最小意外原则”)是,如果
XmlWriter
引发异常,它将尝试重复写入所有嵌套的结束标记


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

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

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

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


在最坏的情况下,当终结器调用Dispose()时,XmlWriter可能已经被释放,您会得到一个异常。所以最好不要使用终结器。

为什么会出现问题?在UsableXmlElement中不需要任何非托管资源,因此不需要任何终结器,我认为……哦,而且不需要将WriteValue和WriteAttribute作为泛型。它什么都不做,因为xwriter.WriteValue总是用对象参数调用。从未听说过它被称为“最小惊喜原则”。我以后会用这个表达:)