2014-09-23 14 views
5

Hãy xem xét một đoạn mã như:Có an toàn khi sử dụng ContinueWith như một hoạt động "cuối cùng" không?

private Task<string> Download() 
{ 
    var wc = new WebClient(); 
    Task<string> backgroundDownload = wc.DownloadStringTaskAsync(this.Uri); 
    // Make sure the WebClient is disposed no matter what. 
    backgroundDownload.ContinueWith((downloadTask) => { wc.Dispose(); }); 
    return backgroundDownload; 
} 

Tôi có thể chắc chắn rằng các cuộc gọi WebClient.Dispose() xảy ra và rằng bất kỳ ngoại lệ sản xuất được rethrown cho người gọi, nếu như không có cuộc gọi đến ContinueWith?

Khách hàng có thể quan sát số ContinueWith này không? (ví dụ: sau đó sẽ gọi tới số ContinueWith xóa cuộc gọi Vứt bỏ?)

+1

Bạn đã thử mã của mình chỉ bằng cách thêm một Console.WriteLine hoặc MessageBox.Show in * ContinueWith *? –

+1

Tại sao không chỉ sử dụng đang chờ? – VoteCoffee

+1

Ngoài ra, nếu bạn sử dụng chờ đợi, bạn có thể thực hiện việc sử dụng với wc và tạo một khối try/catch ở bất cứ đâu có ý nghĩa. – VoteCoffee

Trả lời

11

Với mã mà bạn có, bạn có thể chắc chắn rằng việc tiếp tục sẽ được kích hoạt bất kể mã đã hoàn thành thành công, bị hủy hoặc ném ngoại lệ .

Bài toán có khả năng là với giải pháp mà bạn có là các lần tiếp tục khác có khả năng chạy, trước, trong hoặc sau khi máy khách web được xử lý. Nếu bạn không gặp sự cố với các lần tiếp tục khác đang chạy trước khi quá trình dọn dẹp này chạy, thì những gì bạn có là tốt. Nếu đó là một vấn đề thì bạn sẽ cần phải trả lại sự tiếp tục, không phải nhiệm vụ ban đầu, nhưng bạn cũng sẽ cần phải truyền đạt kết quả (và ngoại lệ/hủy bỏ) một cách chính xác. Việc sử dụng async làm cho tất cả các cách này dễ dàng hơn:

private async Task<string> Download() 
{ 
    using(var wc = new WebClient()) 
     return await wc.DownloadStringTaskAsync(this.Uri); 
} 
0

Trước hết, việc tiếp tục sẽ được thực hiện ngay cả khi một ngoại lệ thường xuyên xảy ra. Tuy nhiên, nó ít có khả năng chạy hơn là một khối cuối cùng thường xuyên trong trường hợp của các điều kiện đặc biệt như một OutOfMemoryException.

Bây giờ tôi sẽ không cố gắng vứt bỏ webclient. Hãy nhớ rằng việc vứt bỏ là một tối ưu hóa, bởi vì tài nguyên gốc sẽ được xử lý bởi trình hoàn thiện. Lý do duy nhất chúng tôi đang xử lý là một finalizer là tốn kém bởi vì nó gây ra một GC thứ hai vượt qua.

Nhưng để thực hiện tối ưu hóa, hệ thống có thể phải tạo chủ đề mới. Bên cạnh đó bạn có thể kéo dài tuổi thọ của webclient của bạn rất nhiều nếu threadpool được làm đầy với nhiệm vụ chạy dài.

Về cơ bản, bạn phải chọn ít hơn của hai tệ nạn và tôi không tin rằng một ít GC chạy là giá trị những gì bạn đang làm. Bạn nên xem xét quyết định này trong ngữ cảnh của ứng dụng của bạn.

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