2011-10-19 13 views
10

Napotkano tę regułę FxCop przedtem i nie byłem zadowolony z tego, jak rozwiązać problemy (thread1, thread2). Mam teraz inny przypadek, w którym muszę poprawić naruszenia rodzaju CA1819.CA1819: Właściwości nie powinny zwracać tablic - Jaka jest właściwa alternatywa?

szczególności mam algorytm-bibliotekę, wykonuje pewne analityczne obliczeń na krzywej (x, y), z publiczną „obiektu wejściowego” tak:

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

X i Y właściwości tego obiektu są używane w setkach lokalizacji w bibliotece, zazwyczaj przy użyciu indeksów. Obiekt wejściowy nigdy nie jest modyfikowany przez algorytmy, ale w rzeczywistości nie powinno to mieć znaczenia. Również, .Length jest dość często nazywane. Jest to biblioteka matematyczna, a double[] jest rodzajem standardowego typu danych. W każdym razie naprawa CA1819 będzie wymagała sporo pracy.

Pomyślałem o użyciu List<double>, ponieważ listy obsługują indeksowanie i są dość podobne do tablic, ale nie jestem pewien, czy może to spowolnić algorytmy, czy też FxCop będzie zadowolony z tych list.

Jaki jest najlepszy sposób na zastąpienie tych właściwości w postaci double[]?

+0

@skk że to „thread1” linki pytanie ... – AakashM

+0

(należy pamiętać, że trzeba kodować formacie kątowniki, aby mogły się pojawić) – AakashM

Odpowiedz

7

Jeśli jest tylko do odczytu dla konsumenta zewnętrznego i konsument nie chce uzyskać do niego dostępu przez indeks, najlepiej jest mieć publiczną właściwość tylko do odczytu typu IEnumerable<> z metodami do dodawania i usuwania, w ten sposób nie będziesz mieć wystawiać swoją tablicę komuś, z kim można zadzierać.

Jeśli potrzebujesz dostępu do indeksatorów, wówczas wystaw go jako właściwość tylko do odczytu typu IList<> i prawdopodobnie zwróć instancję ReadOnly, metodami dodawania i usuwania.

W ten sposób można zachować enkapsulacji listy wewnętrznego i konsumentów pozwalają uzyskać do niego dostęp tylko do odczytu w sposób

+1

Dziękuję za to wejście, to właśnie zrobiłem .. szczególnie dlatego, że istnieje inna reguła FxCop (CA2227, http://msdn.microsoft.com/de-de/library/ms182327.aspx), która zmusza mnie do Zrób tak. ;) – Efrain

+1

Osobiście używałbym IEnumerable , jeśli chciałem sugerować rozmówcy, że nieruchomość może być leniwie oceniona. Prawdopodobnie nie jest tak w przypadku OP, więc wolałbym IList , wspierany przez pole ReadOnlyCollection , jeśli lista powinna być tylko do odczytu. – Joe

+0

Dokładnie @Joe, co dokładnie miałem na myśli :) –

1

Jako swój link sugeruje:

Aby naprawić naruszenie tej zasady, albo zrobić z obiektem metodę lub zmienić właściwość zwraca kolekcję.

Korzystanie z kolekcji, takiej jak List, nie powinno mieć znaczącego wpływu na wydajność.

+3

FxCop nie lubią '' Lista albo - wolą 'IList '. – Joe

+0

Dzięki Joe, nie używamy FxCop, ale to ma sens – devdigital

+0

Zgodnie z @Joe Myślę, że zmiana wartości zwracanej przez twoje właściwości na IList nie powinna mieć żadnego wpływu na inny kod, który ma być rekompilowany/zmieniony, i rozwiązać FxCop Wydanie .. – VS1

0

Dużym problemem tutaj nie jest tak naprawdę to, co robi z biblioteki wartości (co jest potencjalnym problemem, choć o wiele łatwiejszy w zarządzaniu), ale raczej to, co mogą zrobić rozmówcy z wartościami. Jeśli musisz traktować je jako niezmienne, musisz upewnić się, że konsument biblioteki nie może zmienić zawartości po pierwotnym przypisaniu. Łatwą poprawką byłoby utworzenie interfejsu, który odsłania wszystkie elementy tablicy używane przez bibliotekę, a następnie utworzenie niezmiennej klasy opakowania dla tablicy implementującej ten interfejs w klasie InputObject. np.:

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; } 
    } 

    //... 
} 

elementów w swoim „niezmiennych” zawartości tablicy nadal będzie zmienny jeśli T jest zmienny, ale przynajmniej jesteś bezpieczny dla typu double.

+0

Wydaje się, że overkill tworzy swój własny interfejs (IArray), zamiast używać podobnego IList'a , który już istnieje w strukturze. – Joe

+0

@Joe: IList udostępnia operacje modyfikacji listy. Przedmioty można dodawać, usuwać i zamieniać. Oczywiście można rzucić wyjątek NotSupportedException dla każdego z punktów mutacji, ale to nie jest szczególnie uprzejmy sposób traktowania użytkowników API. A poważnie, jak trudno jest dodać interfejs? –

+0

to także własność IsReadOnly, która pozwala abonentowi dzwoniącemu uniknąć wyjątku NotSupportedException. Idiomatycznym sposobem radzenia sobie z tym w .NET jest odsłonięcie tylko odczytu IList , prawdopodobnie wspieranego przez ReadOnlyCollection . Twoja obecna implementacja ma wiele słabych punktów, w tym brak implementacji IEnumerable , ICollection i IList , czego można by się spodziewać po klasie tablicowej. Możesz poświęcić czas na ich implementację, ale dlaczego miałbyś to zrobić, gdy Framework zawiera już wszystko, czego potrzebujesz? – Joe

0

Czasami FxCop z mojego punktu widzenia exagerates.

Wszystko zależy od tego, co musisz zrobić, jeśli piszesz złożony system, w którym wymagane jest bezpieczeństwo i bardzo czysty kod, powinieneś zwrócić wersję tylko do odczytu z tej tablicy. To znaczy, rzuć tablicę jako IEnumerable jak sugeruje devdigital lub użyj dobrego pomysłu ImmutableArray of Mohamed Abed, który wolę.

Jeśli piszesz oprogramowanie, które wymaga wysokiej wydajności ... nie ma nic lepszego niż tablica dla wydajności w języku C#. Tablice mogą być o wiele wydajniejsze do iteracji i czytania.

Jeśli występy są naprawdę ważne, sugeruję, aby zignorować to ostrzeżenie. Jest nadal legalne, również jeśli nie jest zbyt czyste, aby zwrócić tablicę tylko do odczytu.

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

Jest to bardzo szybkie dla dużych tablic w języku C#: zapobiega sprawdzaniu granic tablic. Będzie działać tak, jak zrobi to skompilowany kod C.

Zawsze chciałem typu "tablicy tylko do odczytu" w języku C# :), ale nie ma nadziei, aby go zobaczyć.

+0

"Zawsze chciałem typu" tablicy tylko do odczytu "w języku C#" - ReadOnlyCollection jest funkcjonalnie równoważne z tablicą tylko do odczytu. – Joe

+0

Absolutnie prawdziwe, ale nie tak dużo w przedstawieniach, tablice mają specjalne "shortcust" w JIT. –

Powiązane problemy