Применяется ли рекомендация Кшиштофа к конструкторам? Если да, то как правильно это реализовать?
We recommend using Collection, ReadOnlyCollection, or KeyedCollection for outputs and properties and interfaces IEnumerable, ICollection, IList for inputs.
Например,
public ClassA
{
private Collection<String> strings;
public Collection<String> Strings { get { return strings; } }
public ClassA(IEnumerable<String> strings)
{
this.strings = strings; // this does not compile
this.strings = strings as Collection<String>; // compiles (and usually runs?)
}
}





Вам следует избегать опускания; в вашем примере я бы предложил, чтобы тип вашего параметра конструктора соответствовал (должен быть таким же) типу данных вашего члена (например, либоCollection<String>или жеIEnumerable<String>).
Или есть решение Марка, которое отличается: поскольку решение Марка означает, что данные вашего члена - это не только другой тип, но и другой экземпляр (т.е. если вы изменяете данные члена, то вы изменяете копию исходной коллекции , не редактируя саму исходную коллекцию; аналогично, если исходная коллекция была изменена после того, как вы сделали копию, ваша локальная копия / данные члена не включают это последующее изменение исходной коллекции).
Вам не следует использовать версию as - вы должны либо принять и сохранить что-то повторяющееся, например IList<T>, либо создать новую локальную коллекцию данных:
this.strings = new Collection<string>();
foreach(string s in strings) { this.strings.Add(s); }
Собственно, я бы и сам использовал List<T>; тогда вы можете сделать (хотя это не причина использовать List<T>):
this.strings = new List<string>(strings);
Обратите внимание, что массив также реализует IList <T> и ICollection <T>; но да, очень легко получить строго типизированную коллекцию из IEnumerable <T>
Если вы храните коллекцию, я предпочитаю использовать ICollection в качестве входных данных.
Вероятно, все дело в том, чтобы не раскрывать слишком много вашей реализации. В идеале, если вы разрабатываете общедоступный API, вы должны предоставлять только минимум своей реализации. Если вы вернете полный интерфейс List, у пользователя общедоступного API будет множество способов возиться с внутренностями ваших классов способами, которые вы, возможно, не планировали.
----редактировать----
Почему бы не принять параметр типа IEnumerable<String> и не передать его при поиске?
public ClassA
{
private IEnumberable<String> strings;
public Collection<String> StringCollection {
get { return (Collection<String>) strings; }
}
public ClassA(IEnumerable<String> strings)
{
this.strings = strings;
}
}
Гипс может не всегда работать, правда? В частности, если IEnumerable не имеет конца (реализация с использованием Random) или если источник является внешним и может иметь тайм-аут (сетевой ресурс, веб-служба и т. д.).
Я вроде как согласен с Пейдж.
Я согласен с тем, что вы должны передать IEnumerable в качестве входных данных (таким образом вы поддерживаете любую перечисляемую коллекцию).
Но то, что вы делаете выше со свойством StringCollection, для меня не имеет смысла - вы опускаетесь, что не сработает.
-Матт
Я считаю, что по возможности следует избегать понижения. Если класс хранит ввод как конкретный класс «Коллекция» (что означает, что этот класс работает с «Коллекцией», то я думаю, что более естественным будет просто принять ввод типа «Коллекция» вместо аналога интерфейса.
Это перекладывает ответственность за отрицательное отношение (при необходимости) обратно к потребителю, который должен знать, что он делает, если он это делает.
С другой стороны, я бы сказал, что принятие ввода в качестве интерфейса лучше, чем конкретный класс, поскольку это позволяет более гибко вводить фиктивные объекты. Однако для этого потребуется, чтобы внутренние компоненты класса зависели от интерфейса, а не от конкретного класса (таким образом, в примере переменная-член будет иметь IEnumerable вместо Collection).
Я согласен с yapiskan, что решение Марка фактически изменило использование, создав копию ввода и, таким образом, изменилась ответственность:
Раньше: входные данные постоянно используются между потребителем и этим классом. Таким образом, изменение ввода "разделяется" между потребителем и этим классом.
После: понимание этого класса ввода отделяется от потребителя после вызова конструктора.
Мне нравится идея внутреннего использования IList <T> ... есть несколько способов принять массив (который является IEnumerable) и получить строго типизированную общую коллекцию.