2011-10-19 21 views
10

Tôi đã gặp quy tắc FxCop này trước đây và không thực sự hài lòng với cách giải quyết các vi phạm (thread1, thread2). Bây giờ tôi có trường hợp khác mà tôi cần sửa các vi phạm loại CA1819.CA1819: Thuộc tính không được trả về mảng - Giải pháp thay thế phù hợp là gì?

Cụ thể, tôi có một thuật toán-thư viện mà thực hiện một số tính toán phân tích trên một đường cong (x, y), với một "đối tượng đầu vào" công cộng như thế này:

public class InputObject 
{ 
     public double[] X { get; set; } 
     public double[] Y { get; set; } 
     // + lots of other things well 
} 

X và Y thuộc tính của đối tượng này là được sử dụng trong hàng trăm vị trí trong thư viện, thường sử dụng các chỉ mục. Các đối tượng đầu vào không bao giờ được thay đổi bởi các thuật toán, nhưng thực sự nó không quan trọng nếu như vậy. Ngoài ra, .Length được gọi là khá thường xuyên. Đó là một thư viện toán học và double[] là loại dữ liệu chuẩn trong đó. Trong mọi trường hợp, việc sửa CA1819 sẽ yêu cầu khá nhiều công việc.

Tôi đã nghĩ về việc sử dụng List<double>, vì danh sách hỗ trợ lập chỉ mục và khá giống với mảng nhưng tôi không chắc liệu điều này có làm chậm thuật toán hay không hoặc FxCop có hài lòng với những Danh sách đó hay không.

Tùy chọn nào tốt nhất để thay thế các thuộc tính double[] này?

+0

@skk đó là 'thread1' câu hỏi liên kết đến ... – AakashM

+0

(lưu ý rằng bạn phải mã định dạng dấu ngoặc nhọn để chúng xuất hiện) – AakashM

Trả lời

7

Nếu chỉ đọc đối với người tiêu dùng và người tiêu dùng bên ngoài không muốn truy cập theo chỉ mục thì tốt nhất là có thuộc tính chỉ đọc công khai thuộc loại IEnumerable<> với trình tiếp cận phương thức để thêm và xóa, theo cách này bạn sẽ không có để lộ mảng của bạn với ai đó để gây rối.

Nếu bạn cần truy cập vào các chỉ mục, hãy hiển thị nó dưới dạng thuộc tính chỉ đọc của loại IList<> và có thể trả về một phiên bản ReadOnly, với các phương thức để thêm và loại bỏ.

Bằng cách này bạn giữ đóng gói của danh sách nội bộ và cho phép người tiêu dùng để truy cập vào nó trong một cách duy nhất

+1

Cảm ơn cho đầu vào đó, đó là những gì tôi đã làm .. đặc biệt là vì có một quy tắc FxCop (CA2227, http://msdn.microsoft.com/de-de/library/ms182327.aspx), mà buộc tôi phải làm như vậy. ;) – Efrain

+1

Cá nhân tôi sẽ chỉ sử dụng IEnumerable nếu tôi muốn ngụ ý đến người gọi rằng một thuộc tính có thể được đánh giá lười biếng. Có lẽ không phải là trường hợp trong ví dụ của OP, vì vậy tôi muốn IList , được hỗ trợ bởi một trường ReadOnlyCollection nếu danh sách phải là chỉ đọc. – Joe

+0

Chính xác @ Joe rằng những gì tôi có nghĩa là chính xác :) –

1

Như liên kết của bạn gợi ý:

Để khắc phục vi phạm quy tắc này, hoặc là làm cho tài sản một phương pháp hay thay đổi sở hữu để trở về một bộ sưu tập.

Sử dụng bộ sưu tập như List sẽ không có tác động đáng kể đến hiệu suất.

+3

FxCop sẽ không thích 'Danh sách ' hoặc - thích 'IList '. – Joe

+0

Cảm ơn Joe, chúng tôi không sử dụng FxCop, nhưng điều này có ý nghĩa – devdigital

+0

Theo @Joe tôi nghĩ việc thay đổi giá trị trả lại của thuộc tính của bạn thành IList sẽ không có bất kỳ tác động nào trên mã khác được biên dịch/thay đổi và giải quyết FxCop vấn đề .. – VS1

0

đọc Vấn đề lớn ở đây là không thực sự những gì thư viện của bạn làm với các giá trị (mà là một vấn đề tiềm ẩn, mặc dù có thể quản lý nhiều hơn), nhưng thay vào đó người gọi có thể làm gì với các giá trị. Nếu bạn cần đối xử với họ như là bất biến, thì bạn cần đảm bảo rằng người tiêu dùng thư viện không thể thay đổi nội dung sau bài tập ban đầu của họ. Việc sửa chữa dễ dàng ở đây sẽ là tạo ra một giao diện cho thấy tất cả các thành viên mảng mà thư viện của bạn sử dụng, sau đó tạo một lớp bao bọc bất biến cho một mảng thực hiện giao diện này để sử dụng trong lớp InputObject của bạn. ví dụ::

public interface IArray<T> 
{ 
    int Length { get; } 

    T this[int index] { get; } 
} 

internal sealed class ImmutableArray<T> : IArray<T> 
    where T : struct 
{ 
    private readonly T[] _wrappedArray; 

    internal ImmutableArray(IEnumerable<T> data) 
    { 
     this._wrappedArray = data.ToArray(); 
    } 

    public int Length 
    { 
     get { return this._wrappedArray.Length; } 
    } 

    public T this[int index] 
    { 
     get { return this._wrappedArray[index]; } 
    } 
} 

public class InputObject 
{ 
    private readonly IArray<double> _x; 
    private readonly IArray<double> _y; 

    public InputObject(double[] x, double[] y) 
    { 
     this._x = new ImmutableArray<double>(x); 
     this._y = new ImmutableArray<double>(y); 
    } 

    public IArray<double> X 
    { 
     get { return this._x; } 
    } 

    public IArray<double> Y 
    { 
     get { return this._y; } 
    } 

    //... 
} 

Các yếu tố trong nội dung mảng "bất biến" của bạn vẫn sẽ có thể thay đổi nếu T là có thể thay đổi, nhưng ít nhất bạn đang an toàn cho các loại hình kép.

+0

Có vẻ quá mức cần thiết để tạo giao diện riêng của bạn (IArray) thay vì sử dụng IList tương tự đã tồn tại trong khung công tác. – Joe

+0

@Joe: IList cho thấy các hoạt động để sửa đổi danh sách. Các mục có thể được thêm, xóa và hoán đổi. Tất nhiên, người ta có thể ném một NotSupportedException cho mỗi điểm đột biến, nhưng đó không phải là một cách đặc biệt lịch sự để đối xử với người tiêu dùng API. Và nghiêm túc, có bao nhiêu rắc rối là nó thêm một giao diện? –

+0

nó cũng là một thuộc tính IsReadOnly, cho phép người gọi tránh NotSupportedException. Cách thành ngữ để xử lý điều này trong .NET là để hiển thị một chỉ số ILON chỉ đọc, có thể được hỗ trợ bởi ReadOnlyCollection . Việc triển khai hiện tại của bạn có một số điểm yếu, bao gồm việc không triển khai IEnumerable , ICollection và IList , được mong đợi là một lớp mảng. Bạn có thể dành thời gian thực hiện những điều này, nhưng tại sao bạn lại làm như vậy khi Khung đã chứa tất cả những gì bạn cần? – Joe

0

Thỉnh thoảng FxCop từ quan điểm của tôi exagerates.

Tất cả phụ thuộc vào những gì bạn phải làm, nếu bạn đang viết một hệ thống phức tạp nơi yêu cầu bảo mật và mã rất sạch, bạn nên trả về phiên bản chỉ đọc của mảng đó. Đó là, đúc mảng như IEnumerable như gợi ý devdigital hoặc sử dụng ý tưởng tốt ImmutableArray của Mohamed Abed, mà tôi thích.

Nếu bạn đang viết phần mềm yêu cầu hiệu năng cao ... không có gì tốt hơn một mảng cho các buổi trình diễn trong C#. Mảng có thể có hiệu suất cao hơn để lặp lại và đọc.

Nếu buổi biểu diễn thực sự quan trọng, tôi khuyên bạn nên bỏ qua cảnh báo đó. Vẫn còn hợp pháp, cũng nếu không quá sạch sẽ, để trả về một mảng chỉ đọc.

for (int i = 0; i < array.Length; ++i) { k = array[i] + 1; } 

Điều này rất nhanh đối với mảng lớn trong C#: nó tránh kiểm tra giới hạn mảng. Nó sẽ thực hiện rất nhiều như một mã biên dịch C sẽ làm.

Tôi luôn muốn một loại "chỉ đọc" trong C# :) nhưng không có hy vọng để xem nó.

+0

"Tôi luôn muốn một loại" chỉ đọc mảng "trong C#" - một ReadOnlyCollection có chức năng tương đương với một mảng chỉ đọc. – Joe

+0

Hoàn toàn đúng nhưng không nhiều trong buổi biểu diễn, mảng có đặc biệt "rút ngắn" trong JIT. –

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