2012-01-10 17 views
5

Tôi đang sử dụng .net và cần lấy một số văn bản html, vì vậy tôi nghĩ mình sẽ sử dụng HtmlTextWriter và StringWriter cùng nhau để nhận dạng html đúng. Nhưng mặc dù tất cả các cách khác nhau tôi viết mã, tôi vẫn nhận được cảnh báo từ trình phân tích mã tĩnh (sử dụng Microsoft All Rules). Trong các ví dụ mã bên dưới, tôi hiển thị cảnh báo trình phân tích mã trong nhận xét. Để đơn giản hóa mã Tôi không thực sự thực hiện bất kỳ cuộc gọi đến HtmlTextWriter (bạn sẽ thấy một bình luận cho hiệu ứng đó trong mỗi chức năng). Làm thế nào tôi có thể viết mã đúng cách để tránh các cảnh báo?Cách sử dụng StringWriter và HtmlWriter cùng nhau mà không có cảnh báo Phân tích Mã số

// CA2000 : Microsoft.Reliability : In method 'Default.Func1()', object 'stringWriter' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'stringWriter' before all references to it are out of scope. 
public static string Func1() 
{ 
    string html; 
    StringWriter stringWriter; 
    using (var writer = new HtmlTextWriter(stringWriter = new StringWriter())) 
    { 
     // You would do some stuff with the writer here, but not for this example. 

     html = stringWriter.ToString(); 
    } 
    return html; 
} 

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in method 'Default.Func2()'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 45 
public static string Func2() 
{ 
    string html; 
    StringWriter stringWriter = null; 
    try 
    { 
     using (var writer = new HtmlTextWriter(stringWriter = new StringWriter())) 
     { 
      // You would do some stuff with the writer here, but not for this example. 

      html = stringWriter.ToString(); 
     } 
    } 
    finally 
    { 
     if (stringWriter != null) 
      stringWriter.Dispose(); 
    } 
    return html; 
} 

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in 
// method 'Default.Func3()'. To avoid generating a System.ObjectDisposedException 
// you should not call Dispose more than one time on an object.: Lines: 61 
public static string Func3() 
{ 
    string html; 
    using (var stringWriter = new StringWriter()) 
    { 
     using (var writer = new HtmlTextWriter(stringWriter)) 
     { 
      // You would do some stuff with the writer here, but not for this example. 

      html = stringWriter.ToString(); 
     } 
    } 
    return html; 
} 

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in 
// method 'Default.Func4()'. To avoid generating a System.ObjectDisposedException you 
// should not call Dispose more than one time on an object.: Lines: 77 
public static string Func4() 
{ 
    string html; 
    using (StringWriter stringWriter = new StringWriter()) 
    { 
     using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter)) 
     { 
      // You would do some stuff with the writer here, but not for this example. 

      html = stringWriter.ToString(); 
     } 
    } 
    return html; 
} 

// CA2202 : Microsoft.Usage : Object 'stringWriter' can be disposed more than once in 
// method 'Default.Func5()'. To avoid generating a System.ObjectDisposedException you 
// should not call Dispose more than one time on an object.: Lines: 100 
public static string Func5() 
{ 
    string html; 
    StringWriter stringWriter = null; 
    try 
    { 
     stringWriter = new StringWriter(); 
     using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter)) 
     { 
      // You would do some stuff with the writer here, but not for this example. 

      html = stringWriter.ToString(); 
     } 
    } 
    finally 
    { 
     if (stringWriter != null) 
      stringWriter.Dispose(); 
    } 
    return html; 
} 
+0

rất nhiều ý kiến ​​thú vị về [CA2202] (http://msdn.microsoft.com/en-us/library/ms182334.aspx) trên MSDN –

+1

Đáng tiếc là không ai trong số các ý kiến ​​tại Liên kết CA2202 ở trên đã giải quyết cảnh báo với cặp đặc biệt này khi tôi thử chúng. –

+0

Trong [một bài đăng khác] (http://stackoverflow.com/questions/3831676/ca2202-how-to-solve-this-case), Hans Peter viết "Đây không phải là các lỗi thực sự chính xác, các lớp .NET này có khả năng phục hồi nhiều cuộc gọi Dispose(). " Với ý nghĩ đó, tôi bị cám dỗ để làm việc sử dụng hai lần như Func3 hoặc Func4 và ngăn chặn cảnh báo CA2202. –

Trả lời

0

Vì StringWriter là dùng một lần, bạn có thể bọc người viết bên trong của mình với người khác sử dụng.

using (StringWriter stringWriter = new StringWriter()) 
{ 
    using (var writer = new HtmlTextWriter(stringWriter)) 
    { 
     html = stringWriter.ToString(); 
    } 
} 
return html; 
+0

Đó là khá nhiều giống như của mình 'Func3()' và 'Func4()'. –

+0

@JesseC.Slicer oops xấu của tôi, không nhìn thấy func3 và 4 –

+0

Tôi vừa tải xuống FXCop 10.0.30319.1 và viết một đoạn thử nghiệm nhỏ bằng cách sử dụng này và nó là tốt, tôi không thấy bất kỳ vấn đề xử lý. Tôi có một cảnh báo về Mark Wirht StrongName, IFormatProvider, MarkAssembliesWithNeutralResourcesLanguage nhưng không có gì về xử lý. –

1

Sửa Func5 của bạn để thực hiện như sau:

public static string Func5() 
{ 
    string html; 
    StringWriter stringWriter = null; 
    try 
    { 
     stringWriter = new StringWriter(); 
     using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter)) 
     { 
      stringWriter = null; 

      // You would do some stuff with the writer here, but not for this example. 

      html = htmlTextWriter.InnerWriter.ToString(); 
     } 
    } 
    finally 
    { 
     if (stringWriter != null) 
      stringWriter.Dispose(); 
    } 
    return html; 
} 

Điều quan trọng là đặt biến StringWriter null (mà không ảnh hưởng đến InnerWriter của dụ HtmlTextWriter) và sau đó sử dụng InnerWriter. ToString() để lấy HTML.

Đây thực sự chỉ là phiên bản được sửa đổi của mẫu trong bài viết MSDN được tham chiếu trong nhận xét trước nhưng được áp dụng cụ thể cho việc sử dụng của bạn.

1

Thực sự không có cách nào để làm cho mã này tránh được các cảnh báo vì trong trường hợp cụ thể này, việc phân tích mã sai.

Mã đúng là Func3, thêm một thuộc tính CodeAnalysis.SuppressMessage:

// Code Analysis is incorrectly assuming that HtmlTextWriter.Dispose will dispose of the InnerWriter, but it actually does not. 
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] 
public static string Func3() 
{ 
    string html; 
    using (var stringWriter = new StringWriter()) 
    { 
     using (var writer = new HtmlTextWriter(stringWriter)) 
     { 
      // You would do some stuff with the writer here, but not for this example. 

      // I prefer to use writer.InnerWriter as opposed to stringWriter for clarity. 
      html = writer.InnerWriter.ToString(); 
     } 
    } 
    return html; 
} 

Các tài liệu cho CA2202 sử dụng một ví dụ về một StreamWriter xử lý của Stream của nó, đó là chính xác, nhưng HtmlTextWriter không vứt bỏ nó bên trong TextWriter (có thể xác minh bằng cách phân lớp StringWriter và thiết lập một điểm ngắt trong ghi đè Vứt bỏ). Đây là một chút khó hiểu, kể từ khi HtmlTextWriter xuất phát từ TextWriter, và StringWriter cũng xuất phát từ TextWriter (như trái ngược với một StreamWriter và Stream của nó là hai lớp hoàn toàn khác nhau) vậy tại sao HtmlTextWriter cần một InnerWriter? ... nhưng dù sao, đây là cách nó hoạt động . Ngoài ra, tài liệu nói không được ngăn chặn cảnh báo này bởi vì "Ngay cả khi Vứt bỏ đối tượng được gọi là một cách an toàn có thể gọi nhiều lần, việc thực hiện có thể thay đổi trong tương lai." Tuy nhiên, trong trường hợp này Vứt bỏ là không được gọi nhiều lần, vì vậy cảnh báo có thể bị chặn một cách an toàn.

Nhưng đừng dùng từ ngữ của tôi! Đây là bằng chứng:

using System; 
using System.IO; 
using System.Web.UI; 

namespace WebApplication1 
{ 
    public partial class WebForm1 : System.Web.UI.Page 
    { 
     protected void Page_Load(object sender, EventArgs e) 
     { 
      StreamWillBeDisposed(); 
      TextWriterWillNotBeDisposed(); 
     } 

     public static void StreamWillBeDisposed() 
     { 
      Stream stream = new DebugMemoryStream(); 
      using (StreamWriter writer = new StreamWriter(stream)) 
      { 
       // Use the writer object... 
      }// Underlying Stream will be disposed here by the StreamWriter 
     } 

     public static void TextWriterWillNotBeDisposed() 
     { 
      TextWriter stringWriter = new DebugStringWriter(); 
      using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter)) 
      { 
       // Use the writer object... 
      }// Underlying TextWriter will NOT be disposed here by the HtmlTextWriter 
     } 
    } 


    public class DebugMemoryStream : MemoryStream 
    { 
     protected override void Dispose(bool disposing) 
     { 
      // This Stream will be disposed when the StreamWriter is disposed 
      System.Diagnostics.Debugger.Break(); 
      base.Dispose(disposing); 
     } 
    } 

    public class DebugStringWriter : StringWriter 
    { 
     protected override void Dispose(bool disposing) 
     { 
      // This code will never see the light of day 
      System.Diagnostics.Debugger.Break(); 
      base.Dispose(disposing); 
     } 
    } 

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