3

代码是:

using (MemoryStream memorystream = new MemoryStream(bytes))
{
    using (BinaryWriter writer = new BinaryWriter(memorystream))
    {
        writer.Write((double)100.0);
    }
    return memorystream.ToArray();
}

上面的代码不适合正确处理这两个对象吗?

代码分析有用吗?除了关于变量名称和命名空间的垃圾信息之外,它似乎抱怨了很多不现实的事情。我真的在想也许它很有用,我只是错过了重点。

可以解决 MemoryStream 是否被处理(不是)的问题,这是一个示例,其中 VS 代码分析给了我完全相同的警告。显然这里什么都没有处理

public class MyClass : IDisposable
{
   public void DoSomethingElse()
    {

    }

   #region IDisposable Members
   public void Dispose()
   {
       throw new NotImplementedException();
   }
   #endregion
}

public class MyOtherClass : IDisposable
{
    public MyOtherClass(MyClass mc)
    {

    }
    public void DoSomething() { }
}

public void Foo()
{
    using (MyClass mc = new MyClass())
    {
        using (MyOtherClass otherclass = new MyOtherClass(mc))
        {
            otherclass.DoSomething();
        }
        mc.DoSomethingElse();
    }
}
4

5 回答 5

0

如果我猜的话,我会说分析规则的逻辑是确定一种可能性,如下所示:

“您将一次性对象传递给另一个一次性对象的构造函数(因此在语义上暗示所有权的转移)。如果所有权确实被转移给第二个对象,它很可能会将传递给其构造函数的对象在其自己的 Dispose 方法,但你也在处理它。”

你的第二个例子证明它实际上并没有分析第二个对象是否拥有并处置第一个对象,而是这个规则说这种模式有一些语义歧义,因为负责处置第一个对象的代码不再是清除。

dispose 模式具有 alloc/free 和 new/delete 的所有固有缺陷,因为只有一个类应该拥有并因此控制一次性实例的生命周期。

当然,所有纯粹的猜想,但这就是我的阅读方式。

于 2012-06-05T23:50:18.707 回答
0

MemoryStream 包装了一个托管缓冲区,该缓冲区将在将来的某个时间被垃圾收集,无论它是否被处理掉。

IDisposable 实现是 Stream 合同的一部分。它会关闭流,阻止您使用 Read 和 Write 方法,但您仍然可以访问底层字节。(阻止对 ToArray 的调用可能会使其难以与 StreamWriters 一起使用。)使用像 FileStream 这样的非托管资源的 Stream 实现将在文件句柄被处理时释放文件句柄。

代码分析指出,您和 StreamWriter 都在同一个对象上调用 Dispose 并发出警告。这对于 MemoryStream 来说毫无意义,但对于其他一些 IDisposable 实现可能很危险。

您似乎将 IDisposable 接口与垃圾收集混淆了。调用 Dispose 不会释放托管对象,它只是让您的类有机会以确定的方式释放非托管资源。

于 2012-06-06T00:09:52.453 回答
0

关于“如果流已被处理,那么我该如何调用 memorystream.ToArray()”问题的一部分:

MemeoryStream.Dispose 不释放内部缓冲区。它所做的唯一一件事就是通过抛出“Object Disposed”异常来阻止所有 Stream 方法(如 Read)。即以下代码是完全有效的(通常可以为其他管理某种存储的其他 Stream 对象编写访问较低级别存储的类似代码):

MemoryStream memoryStream = new MemoryStream();
using (memoryStream)
{
 // write something to the stream
}
// Note memoryStream.Write will fail here with an exception,
// only calls to get storage (ToArray and GetBuffer) make sense at this point.
var data = memoryStream.ToArray();
于 2012-06-05T23:40:18.337 回答
0

BinaryWriter 不释放 MemoryStream。您需要处理它。在变量中获取 .ToArray 的结果,然后处理 MemoryStream,然后返回结果。或者使用 try/finally 来处理 MemoryStream。

于 2012-06-06T00:23:58.760 回答
-1

我想BinaryWriter.Dispose()会调用它的底层MemoryStream's .Dispose(),然后你using会重新处理它。

至少我认为这会发生。我还没有打开源代码进行BinaryWriter验证,但我一直认为它关闭并处理了它的底层流。


编辑:

这是课程的来源。你可以看到你的内存流被处理在哪里:

二进制流

    public BinaryWriter(Stream output) : this(output, new UTF8Encoding(false, true)) 
    {
    } 

    public BinaryWriter(Stream output, Encoding encoding)
    { 
        if (output==null)
            throw new ArgumentNullException("output");
        if (encoding==null)
            throw new ArgumentNullException("encoding"); 
        if (!output.CanWrite)
            throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable")); 
        Contract.EndContractBlock(); 

        OutStream = output; 
        _buffer = new byte[16];
        _encoding = encoding;
        _encoder = _encoding.GetEncoder();
    } 

    protected virtual void Dispose(bool disposing)
    { 
        if (disposing) 
            OutStream.Close();
    } 

记忆流

    public class MemoryStream : Stream
    {
        ....
    }

溪流

    public virtual void Close()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

要回答您的另一个问题,“如果 MemoryStream 已被处理,为什么您仍然可以调用 .ToArray()”,那么,这个测试通过就好了:

    [TestMethod]
    public void TestDispose()
    {
        var m = new MemoryStream();
        m.WriteByte(120);
        m.Dispose();
        var a = m.ToArray();

        Assert.AreEqual(1, a.Length);
    }

因此,该.ToArray()方法在 dispose 后仍然可以访问。

字节仍然可用。MemoryStreamdispose 只是在内部设置了一些标志,以防止您进一步修改流:

    protected override void Dispose(bool disposing)
    { 
        try {
            if (disposing) {
                _isOpen = false;
                _writable = false; 
                _expandable = false;
                // Don't set buffer to null - allow GetBuffer & ToArray to work. 
            } 
        }
        finally { 
            // Call base.Close() to cleanup async IO resources
            base.Dispose(disposing);
        }
    } 

事实上,请注意来源中有评论:

// Don't set buffer to null - allow GetBuffer & ToArray to work. 

所以这真的回答了这个问题:)

于 2012-06-05T23:22:13.453 回答