CA1819: свойства не должны возвращать массивы - какова правильная альтернатива?

я столкнулся с этим правилом FxCop раньше и не был доволен тем, как решать нарушения (thread1, thread2). У меня теперь есть еще один случай, когда мне нужно исправить нарушения CA1819 вид.

в частности, у меня есть библиотека алгоритмов, которая выполняет некоторые аналитические вычисления на кривой (x, y) с открытым "входным объектом", как это:

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

свойства X и Y этого объекта используются в сотнях расположения в библиотеке, обычно с использованием индексов. Входной объект никогда не изменяется алгоритмами, но на самом деле это не имеет значения. Кроме того,.Length вызывается довольно часто. Это математическая библиотека, и double[] является своего рода стандартным типом данных там. В любом случае, исправление CA1819 потребует довольно большой работы.

Я думал об использовании List<double>, поскольку списками поддерживает индексацию и очень похожи на массивы, но я не уверен, что это может замедлить алгоритмы или будет ли FxCop доволен этими списками.

каков наилучший вариант для замены этих double[] свойства?

4 ответов


если он читается только внешнему потребителю, и потребитель не хочет обращаться к нему по индексу, то лучше всего иметь общедоступное свойство только для чтения типа IEnumerable<> с помощью методов доступа для добавления и удаления, таким образом, вам не придется подвергать свой массив кому-то возиться.

Если вам нужно получить доступ к индексаторам, то выставьте его как свойство только для чтения типа IList<> и, вероятно, возвращает экземпляр ReadOnly с методами добавления и удаления.

этот путь вы держите инкапсуляция внутреннего списка и разрешить потребителю получить к нему доступ только для чтения


Как подсказывает ваша ссылка:

чтобы исправить нарушение этого правила, Сделайте свойство методом или измените свойство, чтобы вернуть коллекцию.

использование коллекции, такой как List не должно оказать существенного влияния на производительность.


большая проблема здесь заключается не в том, что ваша библиотека делает со значениями (что является потенциальной проблемой, хотя и гораздо более управляемой), а в том, что вызывающие могут делать со значениями. Если необходимо рассматривать их как неизменяемые, необходимо убедиться, что потребитель библиотеки не может изменить содержимое после первоначального назначения. Простым решением здесь было бы создать интерфейс, который предоставляет все члены массива, используемые библиотекой, а затем создать неизменяемый класс-оболочку для массива, который реализует этот интерфейс для использования в вашем InputObject класса. например:

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

    //...
}

элементы в вашем" неизменяемом " содержимом массива все равно будут изменяемыми, если t изменяемо, но, по крайней мере, вы в безопасности для типа double.


когда-то FxCop с моей точки зрения exagerates.

все зависит от того, что вам нужно сделать, если вы пишете сложную систему, где требуется безопасность и очень чистый код, вы должны вернуть версию этого массива только для чтения. То есть бросить массив как IEnumerable, как предлагает devdigital или использовать хорошую идею ImmutableArray Мохаммеда Абеда, что я предпочитаю.

Если вы пишете программное обеспечение, требующее высокой производительности... нет ничего лучше, чем массив для выступлений на C#. Массивы могут быть намного более эффективными для итерации и чтения.

Если спектакли очень важны, я предлагаю вам игнорировать это предупреждение. По-прежнему законно, также если не слишком чисто, возвращать массив только для чтения.

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

Это очень быстро для больших массивов в C#: это позволяет избежать проверки границ массива. Он будет выполнять очень много, как скомпилированный код C.

Я всегда хотел, чтобы тип" readonly array " в C# :), но нет надежды увидеть он.