【问题标题】:Returning SqlXml initialized with memory stream返回使用内存流初始化的 SqlXml
【发布时间】:2014-11-19 06:52:54
【问题描述】:

我正在尝试从使用方法本地内存流初始化它的方法返回一个 SqlXml 对象。即

using (Stream memoryStream = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(memoryStream, new XmlWriterSettings { OmitXmlDeclaration = true }))
            {
                serializer.Serialize(writer, myList.ToArray(), ns);
                return new SqlXml(memoryStream);
            }
        }

现在调用它并尝试访问它的字段的方法失败并显示object disposed exception

我快速浏览了SqlXml.cs,发现它只是保留了对描述行为的流的引用。

public SqlXml(Stream value) {
            // whoever pass in the stream is responsible for closing it
            // similar to SqlBytes implementation
            if (value == null) {
                SetNull();
            }
            else  {
                firstCreateReader = true;
                m_fNotNull = true;
                m_stream = value;
            }

我真的很想避免调用者必须传递流并对其生命周期负责。有没有其他方法可以完全初始化 SqlXml 对象并安全地释放内存流?

编辑:

一种可能的解决方案是拥有一个临时 SqlXml 变量,然后通过创建阅读器构造函数使用它来初始化返回对象:

using (Stream memoryStream = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(memoryStream, new XmlWriterSettings { OmitXmlDeclaration = true }))
            {
                serializer.Serialize(writer, myList.ToArray(), ns);
                SqlXml s = new SqlXml(memoryStream);
                return new SqlXml(s.CreateReader());
            }
        }

但这在我看来还是有点笨重。

【问题讨论】:

  • 如果调用者正在请求一个流,他们应该负责处理它。流生成代码不应该负责处理它,因为它不知道何时不再需要流。或许您可以创建一个工厂或使用 IOC 容器来控制流的创建和处理。
  • 是的,但流在内部用于序列化。调用者不应该真正关心方法如何在内部构造 xml(在这种情况下是通过流)。
  • 确实如此。好吧,一旦您开始处理非托管资源,托管内存世界中的事情就会变得不那么简单。也许您可以从这个讨论 IDisposable 以及谁负责处置传递的 IDisposable 实现者的答案中获得一些想法:stackoverflow.com/a/7944828/9732

标签: c# xml


【解决方案1】:

当块退出时,using 语句将在流上调用 dispose。将 MemoryStream 从 using-block 中取出,在 return 之前不会释放。

class Program
{
    static void Main(string[] args)
    {
        var s = GetData();
        var r = s.CreateReader();
        while (r.Read())
        {
            if (r.NodeType == XmlNodeType.Element)
            {
                System.Console.WriteLine(r.Name);
            }
        }
        r.Close();
    }

    private static SqlXml GetData()
    {
        var mem = new MemoryStream();
        //TODO: Deserialize or query data.
        return new SqlXml(mem);
    }
}

【讨论】:

    猜你喜欢
    • 2019-06-20
    • 1970-01-01
    • 2017-12-31
    • 2012-01-30
    • 1970-01-01
    • 2015-06-22
    • 2020-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多