2014-06-12 16 views
6

Nếu tôi có một CryptoStream mà tôi muốn vượt qua trở lại cho người sử dụng, cách tiếp cận ngây thơ sẽ làCryptoStream có thể được trả lại và vẫn có mọi thứ được xử lý đúng không?

public Stream GetDecryptedFileStream(string inputFile, byte[] key, byte[] iv) 
{ 
    var fsCrypt = new FileStream(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read); 
    var rmCrypto = new RijndaelManaged(); 
    var transform = rmCrypto.CreateDecryptor(key, iv); 
    var cs = new CryptoStream(fsCrypt, transform, CryptoStreamMode.Read); 

    return cs; 
} 

Tôi biết rằng khi tôi vứt bỏ các CryptoStream nằm dưới FileStreamwill also be disposed. Vấn đề tôi đang gặp phải là tôi phải làm gì với rmCryptotransform? RijndaelManagedICryptoTransform là các lớp dùng một lần, nhưng việc xử lý luồng không loại bỏ hai đối tượng đó.

Cách chính xác để xử lý tình huống này là gì?

+1

Theo phương pháp của bạn, 'rmCrypto' và 'transform' nên được xử lý sau khi bạn quay trở lại từ' GetDecryptedFileStream' vì chúng là các biến cục bộ trong phương pháp của bạn. –

+1

@YuvalItzchakov Đi ra khỏi phạm vi không có nghĩa là bị xử lý. GC sẽ không hoàn thành hai đối tượng đó cho đến khi tham chiếu cuối cùng tới 'cs' được giải phóng. –

+0

Ồ, tôi không nhìn thấy 'CryptoStream' của bạn đang chấp nhận chúng dưới dạng tham số. –

Trả lời

5

Tôi muốn xem xét việc tạo lớp của riêng bạn kết thúc tốt đẹp luồng và sau đó bạn có thể quản lý việc loại bỏ các luồng này. Đôi khi dọc theo những dòng này (xin lỗi - không biết loại đối tượng biến đổi nằm ngoài đầu của tôi).

public CryptoStreamWrapper : Stream, IDisposable 
{ 
    public CryptoStreamWrapper(CryptoStream stream, RijndaelManaged rmCrypto, IDisposable transform) 
    { 
     this.transform = transform; 
     this.rmCrypto = rmCrypto; 
     this.stream = stream; 
    } 

    public void Dispose() 
    { 
     this.transform.Dispose(); 
     this.rmCrypto.Dispose(); 
     this.stream.Dispose(); 
    } 
} 
+3

Thực ra, điều đó rất giống với giải pháp mà tôi đưa ra sau khi đặt câu hỏi sau khi "hỏi con vịt của tôi". Bạn có thể lấy được 'CryptoStream'. Tôi sẽ đăng câu trả lời. –

+0

@ScottChamberlain: Tôi thích thực tế bạn đang sử dụng vịt cao su! – Ian

+0

Giải pháp tuyệt vời, sắp sửa đăng chính xác điều đó –

5

Ian đánh tôi đến khái niệm cơ bản (go upvote him), nhưng CryptoStream bản thân là không được niêm phong để nó là tầm thường để tạo ra một lớp được thừa kế mà kết thúc tốt đẹp những điều mà cần phải được xử lý.

/// <summary> 
/// Creates a class that creates a <see cref="CryptoStream"/> and wraps the disposing action of all the associated objects 
/// </summary> 
class ReturnableCryptoStream : CryptoStream 
{ 
    private readonly ICryptoTransform _transform; 
    private readonly IDisposable _algorithm; 

    public ReturnableCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode) 
     : this(stream, transform, mode, null) 
    { 
    } 

    public ReturnableCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode, IDisposable algorithm) 
     : base(stream, transform, mode) 
    { 
     _transform = transform; 
     _algorithm = algorithm; 
    } 

    protected override void Dispose(bool disposing) 
    { 
     base.Dispose(disposing); 
     if (disposing) 
     { 
      if (_transform != null) 
       _transform.Dispose(); 

      if (_algorithm != null) 
       _algorithm.Dispose(); 
     } 
    } 
} 

Được sử dụng như

public Stream GetDecryptedFileStream(string inputFile, byte[] key, byte[] iv) 
{ 
    var fsCrypt = new FileStream(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read); 
    var rmCrypto = new RijndaelManaged(); 
    var transform = rmCrypto.CreateDecryptor(key, iv); 
    var cs = new ReturnableCryptoStream(fsCrypt, transform, CryptoStreamMode.Read, rmCrypto); 

    return cs; 
} 
+0

Đánh giá cao ghi chú tín dụng trong câu trả lời của bạn :) – Ian

+0

Suy nghĩ về điều này, điều này thực sự cũng sạch hơn, vì bạn không cần triển khai tất cả các thành viên khác - như Length, ReadByte() v.v. – Ian

+0

Tôi đang nghĩ rằng nó có thể được chính xác hơn để làm transform.Dispose() sau base.Dispose(), vì nếu không bạn đang xử lý somethign rằng lớp cơ sở vẫn có một tham chiếu quá và có thể chọn để thực hiện cuộc gọi trong quá trình xử lý của nó. Tôi không chắc trường thuật toán của bạn là gì (?) Nếu đó là đối tượng ban đầu đã tạo ra ICryptoTransform thì có thể xử lý ngay khi ICryptoTransform được tạo ra, do đó bạn không cần phải giữ lại nó để xử lý sau . – redcalx

Các vấn đề liên quan