2013-03-13 37 views
8

Xét đoạn mã sau:Ngăn chặn để xử lý các đối tượng nhiều lần

using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate)) 
{ 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     // Use the writer object... 
    } 
} 

Khi dòng writer được beeing vứt bỏ nó disposes nội FileStream stream.

Có desgin khác cho việc này khác với MSDN recommendation để xử lý các dòng sử dụng bên ngoài vào khối finally:

Stream stream = null; 
try 
{ 
    stream = new FileStream("file.txt", FileMode.OpenOrCreate); 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     stream = null; 
     // Use the writer object... 
    } 
} 
finally 
{ 
    if(stream != null) 
     stream.Dispose(); 
} 
+5

Bạn có thể gọi Dispose() cho cùng một đối tượng nhiều lần, theo Microsoft. –

+1

@MatthewWatson, một tài liệu tham khảo trích dẫn Microsoft về điều đó sẽ tốt đẹp .. –

+0

@MatthewWatson khi 1nd sử dụng cố gắng vứt bỏ một đối tượng được allready xử lý gây ra lỗi – CloudyMarble

Trả lời

3

Đây là một trường hợp FxCop là mạnh mâu thuẫn với lựa chọn thiết kế trong .NET Framework. Vấn đề được gây ra bởi StreamWriter giả định quyền sở hữu của luồng. Đó là nói chung một sự sụp đổ "trong sự thành công của sự lựa chọn thiết kế", hầu hết các lập trình viên sẽ giả định rằng đóng StreamWriter là đủ để có được dòng xử lý. Đặc biệt như vậy khi họ sử dụng Close() thay vì Dispose().

Hoạt động tốt trong phần lớn các trường hợp. Hầu hết các trường hợp, một cách sử dụng cụ thể ở đây là rất có vấn đề là CryptoStream. Một lớp yêu cầu xả nước và không thể chẩn đoán được sự cố khi luồng cơ bản bị đóng trước khi CryptoStream bị xóa và xử lý. Một trường hợp cảnh báo FxCop sẽ phù hợp, mặc dù nó quá khó hiểu để dễ dàng nhận ra vấn đề cụ thể;)

Và trường hợp chung mà một lập trình viên đã viết phương thức Dispose() của riêng mình và quên làm cho nó an toàn được gọi nhiều lần. Đó là những gì cảnh báo FxCop có ý định mang đến sự chú ý, nó không phải là đủ thông minh để có thể thấy rằng một phương pháp Vứt bỏ là trong thực tế an toàn.

Trong trường hợp cụ thể này, cảnh báo FxCop chỉ là vô ích. Tất cả các khung công tác của .NET Framework được cung cấp Dispose() đều an toàn. FxCop sẽ tự động loại bỏ các cảnh báo này cho mã .NET framework. Nhưng không, Microsoft cũng sử dụng nó. Có thuộc tính [SuppressMessage] trong mã nguồn khuôn khổ .NET.

Làm việc xung quanh cảnh báo quá xấu và dễ xảy ra lỗi. Và vô nghĩa vì không có gì thực sự sai. Hãy nhớ rằng FxCop chỉ là một công cụ chẩn đoán, được thiết kế để tạo ra "bạn đã xem xét thông báo này". Nó không phải là một cảnh sát mà sẽ đưa bạn vào tù khi bạn bỏ qua các quy tắc. Đó là công việc của một trình biên dịch.

Sử dụng thuộc tính [SuppressMessage] để tắt cảnh báo.

+0

Thật buồn cười khi biết rằng Microsoft sử dụng SupressesMessage để ngăn chặn các cảnh báo của nó. rất nhiều người xem các quy tắc này như một kinh thánh lập trình. Trong trường hợp của tôi nó phức tạp hơn khi tôi sử dụng một stringwriter và textxmlwriter, vì vậy tôi sẽ phải giữ chuỗi trong một tempvariable trước khi tôi có thể thiết lập các stringwriter null như đề xuất trên msdn. – CloudyMarble

3

Giải pháp cho trường hợp cụ thể này là để gọi the overload of the StreamWriter constructor that lets you tell it not to dispose the underlying stream.

Thật không may, chỉ dành cho .Net 4.5; bằng không bạn sẽ phải làm những gì bạn đang làm.

Ngoài ra, xem chủ đề này: Is there any way to close a StreamWriter without closing its BaseStream?

Ngẫu nhiên, các mã trong OP không KHÔNG nguyên nhân một ngoại lệ khi tôi thử nó!

Các mẫu dưới đây giả định một thư mục có tên "C: \ TEST" tồn tại:

using System; 
using System.IO; 

namespace Demo 
{ 
    public static class Program 
    { 
     public static void Main(string[] args) 
     { 
      // This does NOT cause any exceptions: 

      using (Stream stream = new FileStream("c:\\test\\file.txt", FileMode.OpenOrCreate)) 
      { 
       using (StreamWriter writer = new StreamWriter(stream)) 
       { 
        writer.Write("TEST"); 
       } 
      } 
     } 
    } 
} 
+0

+1 cho liên kết – CloudyMarble

+0

Tại sao bạn lại nói về ngoại lệ? Đây là cảnh báo phân tích mã. –

+0

Chỉ cần một thông tin: Trong trường hợp của tôi tôi chỉ nhận thấy ngay cả .net 4.5 wouldnt đã giúp tôi kể từ khi "bên trong" dòng trong trường hợp của tôi là XmlTextWriter mà không có lá cờ leaveOpen! – CloudyMarble

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