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

时间:2018-06-08 16:06:33

标签: c# 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类,将所有方法强制转换为私有属性CryptoStream。但这没有成功。它始终打破了对手,在那里我试着在开始时阅读IV。

2 个答案:

答案 0 :(得分:1)

这是您正在尝试做的非常粗略的示例。有很多地方可以改进,但这是一个可以建立的工作样本。

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

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

}

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

        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();
            }
        }

如果运行此示例,您可以看到它使用"Test string"cryptostream写入文件,然后从该文件中读取相同的文本。检查text的值,我们可以看到它仍为"Test string",表示该过程已成功。

答案 1 :(得分:1)

辅助功能怎么样?

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>);