Вы принимаете интерфейсы в качестве параметров конструктора?

Применяется ли рекомендация Кшиштофа к конструкторам? Если да, то как правильно это реализовать?

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?)
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
576
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Вам следует избегать опускания; в вашем примере я бы предложил, чтобы тип вашего параметра конструктора соответствовал (должен быть таким же) типу данных вашего члена (например, либо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> ... есть несколько способов принять массив (который является IEnumerable) и получить строго типизированную общую коллекцию.

Anthony Mastrean 13.01.2009 00:02

Обратите внимание, что массив также реализует IList <T> и ICollection <T>; но да, очень легко получить строго типизированную коллекцию из IEnumerable <T>

Marc Gravell 13.01.2009 11:33

Если вы храните коллекцию, я предпочитаю использовать 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) или если источник является внешним и может иметь тайм-аут (сетевой ресурс, веб-служба и т. д.).

Anthony Mastrean 13.01.2009 00:00

Я вроде как согласен с Пейдж.

Я согласен с тем, что вы должны передать IEnumerable в качестве входных данных (таким образом вы поддерживаете любую перечисляемую коллекцию).

Но то, что вы делаете выше со свойством StringCollection, для меня не имеет смысла - вы опускаетесь, что не сработает.

-Матт

Я считаю, что по возможности следует избегать понижения. Если класс хранит ввод как конкретный класс «Коллекция» (что означает, что этот класс работает с «Коллекцией», то я думаю, что более естественным будет просто принять ввод типа «Коллекция» вместо аналога интерфейса.

Это перекладывает ответственность за отрицательное отношение (при необходимости) обратно к потребителю, который должен знать, что он делает, если он это делает.

С другой стороны, я бы сказал, что принятие ввода в качестве интерфейса лучше, чем конкретный класс, поскольку это позволяет более гибко вводить фиктивные объекты. Однако для этого потребуется, чтобы внутренние компоненты класса зависели от интерфейса, а не от конкретного класса (таким образом, в примере переменная-член будет иметь IEnumerable вместо Collection).

Я согласен с yapiskan, что решение Марка фактически изменило использование, создав копию ввода и, таким образом, изменилась ответственность:

Раньше: входные данные постоянно используются между потребителем и этим классом. Таким образом, изменение ввода "разделяется" между потребителем и этим классом.

После: понимание этого класса ввода отделяется от потребителя после вызова конструктора.

Другие вопросы по теме