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

BinaryWriterはMemoryStreamを破棄しません。あなたはそれを処分する必要があります。変数で.ToArrayの結果を取得し、MemoryStreamを破棄して、結果を返します。または、try/finallyを使用してMemoryStreamを破棄します。

于 2012-06-06T00:23:58.760 に答える
0

MemoryStream は、破棄されるかどうかに関係なく、将来のある時点でガベージ コレクションされるマネージ バッファーをラップします。

IDisposable の実装は、Stream コントラクトの一部です。ストリームを閉じて Read メソッドと Write メソッドを使用できないようにしますが、基になるバイトへのアクセスは引き続き許可されます。(ToArray の呼び出しを防止すると、StreamWriter での使用が困難になる可能性があります。) FileStream のようなアンマネージ リソースを使用する Stream 実装は、破棄されるときにファイル ハンドルを解放します。

コード分​​析は、あなたと StreamWriter の両方が同じオブジェクトで Dispose を呼び出しており、それについて警告していることに注目しています。これは MemoryStream ではほとんど意味がありませんが、他の IDisposable 実装では危険な場合があります。

IDisposable インターフェイスとガベージ コレクションを混同しているようです。Dispose を呼び出してもマネージド オブジェクトは解放されません。クラスにアンマネージド リソースを確定的な方法で解放する機会が与えられるだけです。

于 2012-06-06T00:09:52.453 に答える
0

推測すると、分析ルールのロジックは、次のような可能性を識別していると言えます。

「使い捨てオブジェクトを別の使い捨てオブジェクトのコンストラクターに渡しています(したがって、意味的に所有権の譲渡を暗示しています)。所有権が本当に2番目のオブジェクトに移されている場合、そのコンストラクターに渡されたオブジェクトを破棄する可能性があります。独自の Dispose メソッドですが、あなたもそれを破棄しています。」

2番目の例は、2番目のオブジェクトが最初のオブジェクトの所有権を取得して処分するかどうかを実際に分析していないことを証明していますが、最初のオブジェクトの処分を担当するコードはもはやクリア。

Dispose パターンには、alloc/free および new/delete の固有の落とし穴がすべて含まれています。これは、1 つのクラスのみが所有し、使い捨てインスタンスの有効期間を制御する必要があるためです。

もちろん、すべて純粋な推測ですが、それが私がそれを読んだ方法です。

于 2012-06-05T23:50:18.707 に答える
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 に答える
-1

その基になる'sBinaryWriter.Dispose()を呼び出してから、それを再配置すると思います。MemoryStream.Dispose()using

少なくとも私はそうなると思います。検証のためにソースを開いたことはありませんが、ソースがBinaryWriter閉じられ、その基になるストリームが破棄されたという印象を常に受け​​ていました。


編集:

これは、クラスのソースです。メモリ ストリームが破棄されている場所を確認できます。

BinaryStream :

    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() を呼び出すことができるのか」というさらなる質問の 1 つに答えるために、このテストは問題なくパスします。

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

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

したがって、.ToArray()破棄後もメソッドにアクセスできます。

バイトはまだ利用可能です。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 に答える