将嵌套的 using 语句替换为一个 using 语句

Replace nested using-statement with one using statement

我发现自己在重复这段代码

using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)
{
  using (var aes = AesCryptoServiceProvider() { Key = ... }
  {

    // Read the IV at the beginning of the filestream

    using (var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read)
    {

      // Actual code only using cryptoStream

    }
  }
}

using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
  using (var aes = AesCryptoServiceProvider() { Key = ... }
  {

    // Write the IV at the beginning of the filestream

    using (var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Write)
    {

      // Actual code only using cryptoStream

    }
  }
}

然后我问自己,是否可以用这样的东西代替它

using (var cryptoStream = new MyDecryptionStream(path))
{
  // Actual code
}

实际代码可能会有很大不同。它可以是必须保存的图像或 xml 序列化。

我尝试实现自己的 Stream class,将所有方法转换为私有 属性 CryptoStream。但这没有成功。总是在对应的地方坏掉,我一开始就试着读IV。

这是一个非常粗略的示例,说明您正在尝试做什么。有很多地方可以改进,但这是一个工作示例,您可以希望以此为基础。

首先,我们创建一个实现 IDisposable 的 class。这允许我们在 using 语句中使用此 class。 class 将实例化我们需要的其他三个对象,并自行处理它们。

class MyCryptoStream : IDisposable
{
    private FileStream fileStream = null;
    private AesCryptoServiceProvider aes = null;
    public CryptoStream cryptoStream = null;

    public enum Mode
    {
        Write,
        Read
    }

    public MyCryptoStream(string filepath, Mode mode, byte[] key, byte[] iv = null)
    {
        if(mode == Mode.Write)
        {
            fileStream = new FileStream(filepath, FileMode.Open, FileAccess.Write);
            fileStream.Write(iv, 0, 16);
            aes = new AesCryptoServiceProvider() { Key = key, IV = iv };

            cryptoStream = new CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
        }
        else
        {
            iv = new byte[16];
            fileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read);
            fileStream.Read(iv, 0, 16);
            aes = new AesCryptoServiceProvider() { Key = key, IV = iv };

            cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
        }
    }

    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                if (cryptoStream != null)
                {
                    cryptoStream.Dispose();
                }
                if (aes != null)
                {
                    aes.Dispose();
                }
                if (fileStream != null)
                {
                    fileStream.Dispose();
                }
            }

            // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
            // TODO: set large fields to null.

            disposedValue = true;
        }
    }

    // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
    // ~UsingReduction() {
    //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    //   Dispose(false);
    // }

    // This code added to correctly implement the disposable pattern.
    public void Dispose()
    {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(true);
        // TODO: uncomment the following line if the finalizer is overridden above.
        // GC.SuppressFinalize(this);
    }
    #endregion

}

现在,我们可以像这样使用这个class:

        string path = "..\..\test.txt";
        byte[] key = null;
        byte[] iv = null;
        using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
        {
            key = myAes.Key;
            iv = myAes.IV;
        }
        using (MyCryptoStream ur = new MyCryptoStream(path, MyCryptoStream.Mode.Write, key, iv))
        {
            using (StreamWriter sw = new StreamWriter(ur.cryptoStream))
            {
                sw.Write("Test string");
            }
        }
        string text = string.Empty;
        using (MyCryptoStream ur = new MyCryptoStream(path, MyCryptoStream.Mode.Read, key))
        {
            using (StreamReader sr = new StreamReader(ur.cryptoStream))
            {
                text = sr.ReadToEnd();
            }
        }

如果您 运行 这个例子,您可以看到它使用 cryptostream"Test string" 写入文件,然后从该文件读回相同的文本。查看text的值,仍然是"Test string",说明程序成功。

辅助函数怎么样?

public static TResult ReadFileUsingCrypto<TResult>(string path, KeyThing key, Func<CryptoStream, TResult> use)
{
    using (var fileStream = new FileStream(path, FileMode.Open, FileAccesa.Read))
    using (var aes = new AesCryptoServiceProvider(){...}))
    using (var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
    {
        return use(cryptoStream);
    }
}

然后

var result = ReadFileUsingCrypto(“myFile”, key, crypto => <use crypto here and return result>);