Search code examples
c#memorystreamusing-statementcryptostream

How the MemoryStream declared in outer using statement is still available after inner using statement closes?


The Microsoft docs have the following piece of code on this page:

https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream?view=netframework-4.7

The most inner 'using' statement suppose to Dispose csEncrypt, which in it's turn suppose to Dispose the msEncrypt stream. However, right after the most inner using statement scope the msEncrypt is still alive and is used (the ToArray() of it is called).

The Microsoft document clearly states: "The StreamWriter object calls Dispose() on the provided Stream object when StreamWriter.Dispose is called.". The latter means that the csEncrypt is also disposed/closed, which in its turn closes the msEncrypt (https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/cryptostream.cs,23052627697efb77, Can a CryptoStream leave the base Stream open?).

Then please explain how we can still call the "msEncrypt.ToArray();" after the end of scope of the innermost using statement?

using (MemoryStream msEncrypt = new MemoryStream())
{
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
    {
        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
        {
            //Write all data to the stream.
            swEncrypt.Write(plainText);
        }

        encrypted = msEncrypt.ToArray();
    }
}

Solution

  • please explain how we can still call the "msEncrypt.ToArray();" after the end of scope of the innermost using statement?

    Because the documentation promises us that that's so:

    This method works when the MemoryStream is closed

    (It's important to understand that in the context of Stream objects, the Close() and Dispose() methods are effectively synonymous.)

    More generally, it's important to keep in mind that IDisposable.Dispose() has nothing at all to do with the lifetime of the object implementing that interface. The only thing it does is allow your code to inform the object when it is "done using it", to allow it to clean up (typically, freeing unmanaged resources…for any managed objects, there is no need because the CLR's garbage collector will take care of those).

    Any object implementation is allowed to do whatever it feels appropriate when Dispose() is called. While it is typical that an object would become unusable after Dispose() is called, this is not required. And indeed, there are good reasons to allow at least some methods in MemoryStream, like ToArray(), to still be usable after the object has been disposed (but note that even for MemoryStream, most of the object's members are unusable after disposal…ToArray() is a special case).

    In any case, calling Dispose() never will invalidate the object reference itself. The object reference will always remain valid as long as the object itself is reachable. It's up to the object itself to decide what should happen if any other code calls one of its members after it's been disposed. Most of the time, ObjectDisposedException will be thrown, but in some specific cases it makes sense to allow code to access members that are primarily useful only when the code is nearly done with the object and its main purpose has been been served. MemoryStream.ToArray() is such a member.

    See possible duplicate questions:
    Multiple using block, is this code safe?
    Call to MemoryStream.GetBuffer() succeeds even after MemoryStream.Close(); Why?
    Why can you still use a disposed object?
    Clarify some things about IDisposable interface. Is instance (must be) equals null after calling Dispose?

    Also see closely-related question:
    CA2202, how to solve this case