2014-10-29 20 views
14

Tôi sử dụng phân tích mã tĩnh trong các dự án của chúng tôi để kiểm tra vi phạm mã. Một trong những quy tắc được sử dụng rộng rãi là CA2213, kiểm tra việc xử lý đúng các trường dùng một lần.Quy tắc phân tích mã CA2213 và thuộc tính tự động triển khai

Tôi nhận thấy CA2213 không kiểm tra việc xử lý các thuộc tính được tự động triển khai.

Hơn nữa CA2213 không kiểm tra việc loại bỏ các trường hoặc thuộc tính được tự động triển khai nếu lớp kế thừa từ lớp thực hiện IDisposable và không ghi đè phương thức Vứt bỏ.

thực tế ví dụ:

public sealed class Good : IDisposable { 
    private Font font; 
    public Font Font { 
     get { return font; } 
     set { font = value; } 
    } 
    public Good() { font = new Font("Arial", 9); } 
    public void Dispose() { /* Do nothing */ }  // CA2213 
} 

public sealed class Bad : IDisposable { 
    public Font Font { get; set; } 
    public Bad() { Font = new Font("Arial", 9); } 
    public void Dispose() { /* Do nothing */ }  // No warning 
} 

Đã có người khác gặp phải hành vi này? Đây có phải là do thiết kế hoặc lỗi trong quy tắc CA2213 không?

Trả lời

0

Công cụ phân tích tĩnh được điều chỉnh để cân bằng giữa việc tạo quá nhiều kết quả dương tính giả (tức là phát ra mã hoàn toàn tốt) và quá nhiều âm bản sai (tức là thiếu các vấn đề thực trong mã).

Hãy lấy một ví dụ đơn giản:

// CA2213 detects an issue 
class OwnsTheField : IDisposable 
{ 
    private MemoryStream f = new MemoryStream(); 
    public void Dispose() {} 
} 

Rõ ràng trong trường hợp này là một vấn đề cần được báo cáo, và đó thực sự là trường hợp.

Bây giờ, chúng ta hãy làm cho mọi việc hơi phức tạp hơn:

// CA2213 does not detect 
class FieldIsInjected : IDisposable 
{ 
    private MemoryStream f; 
    public FieldIsInjected(MemoryStream p) 
    { 
     f = p; 
    } 
    public void Dispose() { } 
} 

Trong trường hợp này, có thể không phải là một vấn đề với không xử lý f. Nếu p được xử lý đúng cách bởi người gọi, sau đó tất cả mọi thứ công trình như mong đợi:

using (var p = new MemoryStream()) 
{ 
    using (var x = FieldIsInjected(p)) { /* ... */ } 
} // p is properly disposed 

Thường xuyên hơn không, hành vi chính xác (bao gồm cả việc xử lý mọi trường hợp góc) sẽ không được ghi lại, như là một tài liệu hướng dẫn đầy đủ sẽ là quá tốn kém để duy trì theo thời gian. Ví dụ: ngoại lệ này được đề cập rõ ràng trong https://msdn.microsoft.com/en-us/library/ms182328.aspx

+0

Trong trường hợp bạn liệt kê, Phân tích mã vẫn yêu cầu bạn xử lý 'f' theo cách nào đó, thường bằng cách loại bỏ thủ công và lưu ý trong trường hợp rằng trường được tiêm không thuộc sở hữu của lớp hiện tại. Đây là một giải pháp tốt cho tôi. Những gì không phải là một giải pháp tốt là không hiển thị các vấn đề phân tích mã ở tất cả, chỉ đơn giản bởi vì 'f' là một autoproperty hoặc bởi vì FieldIsInjected xuất phát từ một lớp IDisposable và không ghi đè Vứt bỏ (bool) –

0

Quy tắc là từ .net framework 2auto properties are from C# 3, được thêm vào đặc tả ngôn ngữ sau khi quy tắc được tạo. Quy tắc được xác định theo các trường không thuộc tính, do đó, có vẻ như đó là do cập nhật nhưng hoạt động như được chỉ định hiện tại.

This Question on disposing properties dường như cho thấy rằng các thuộc tính triển khai IDisposable không nhất quán trong khuôn khổ.

4

Máy phân tích mã không có giới hạn, mã trình bày trong mã này là nó cần tạo cảnh báo có thể thao tác. Một trong những lập trình viên thực sự có thể theo dõi để sửa mã của anh ta. Một vấn đề quan trọng với trình phân tích mã hiện tại là nó không phân tích mã nguồn, nó hoạt động từ assembly được tạo ra bởi trình biên dịch. Đó là tốt đẹp, nó hoạt động cho bất kỳ ngôn ngữ. Nhưng không ai sẽ muốn cảnh báo này:

CA2213 lĩnh vực Disposable nên được xử lý
'Bad' chứa lĩnh vực <Font>k__BackingField đó là kiểu IDisposable: 'Font'. Thay đổi phương thức Vứt bỏ thành 'Xấu' để gọi Vứt bỏ hoặc Đóng trên trường này.

Yikes, tất nhiên không có trường như vậy trong chương trình. Để tạo một thông điệp tốt hơn, người phân tích sẽ phải tìm ra rằng trường <Font>k__BackingField trong siêu dữ liệu thực tế được liên kết với thuộc tính được tự động triển khai Font. Không có gì trong siêu dữ liệu làm cho kết nối đó rõ ràng. Trường chỉ mang thuộc tính [CompilerGenerated] và tên trường được tạo tự động là một chi tiết triển khai trình biên dịch. Trình biên dịch ngôn ngữ khác nhau tạo ra các tên khác nhau.

Đây là loại sự cố yêu cầu phân tích mã nguồn, chứ không phải phân tích IL như được triển khai hiện tại. Cơ hội là gõ cửa, phân tích mã nguồn sẽ dễ thực hiện hơn nhiều với Roslyn hiện nay. VS2015 là phiên bản VS đầu tiên hỗ trợ phân tích "Live Code". Tôi không biết liệu nó có tìm kiếm lỗi kiểu CA2213 hay không.

+0

Có một giải pháp có thể làm việc cho VS2012? Chẳng hạn như quy tắc StyleCop kích hoạt trên AutoProperties kế thừa từ IDisposable? –

+0

Tôi đang đánh dấu câu trả lời này vì tiền thưởng vì nó giải thích sự khó khăn cho công cụ Phân tích Mã đối với phân tích IL. Câu trả lời có vẻ là theo mặc định, bạn không thể bao gồm các vấn đề mà tôi và Zvonko đã vạch ra. Nếu trong tương lai tôi tìm ra phương pháp tạo quy tắc StyleCop để xử lý điều này hoặc chúng tôi chuyển sang Roslyn và tôi có thời gian để thêm quy tắc phân tích mã tùy chỉnh, sau đó tôi sẽ đảm bảo cập nhật. –

+0

Tôi đồng ý, giải pháp không thẳng về phía trước. Để phân tích càng nhiều trường hợp càng tốt khi phân tích mã nguồn (và để ngăn mã xấu đi tới VCS của chúng tôi), tôi kết hợp các cách tiếp cận khác nhau: phân tích mã nguồn (StyleCop), phân tích IL (FxCop), kiểm tra đơn vị với sự phản chiếu trên các loại cụ thể), mã chương trình bổ sung (chỉ thực thi trong bản dựng gỡ lỗi hoặc khi trình gỡ rối được đính kèm) và các kịch bản PowerShell tùy chỉnh. Tất nhiên check-in gated được kích hoạt và làm tất cả điều đó. – Zvonko

0

Công cụ phân tích hoàn toàn có khả năng đi bộ giữa thuộc tính và trường hậu thuẫn của nó. Nó chỉ không có logic để làm điều đó, và do đó bỏ lỡ một cơ hội cho một cảnh báo. Tệ hơn nữa, nó phát ra một false warning nếu một tài sản được xử lý đúng cách là chỉ có.

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