Відповіді на такі запитання: List <T> або IList <T> завжди схожі на те, що повернення інтерфейсу краще, ніж повернення конкретної реалізації колекції. Але я борюся з цим. Примірник інтерфейсу неможливий, тому якщо ваш метод повертає інтерфейс, він фактично все одно повертає конкретну реалізацію. Я трохи експериментував із цим, написавши 2 невеликі методи:
public static IList<int> ExposeArrayIList()
{
return new[] { 1, 2, 3 };
}
public static IList<int> ExposeListIList()
{
return new List<int> { 1, 2, 3 };
}
І використовуйте їх у моїй тестовій програмі:
static void Main(string[] args)
{
IList<int> arrayIList = ExposeArrayIList();
IList<int> listIList = ExposeListIList();
//Will give a runtime error
arrayIList.Add(10);
//Runs perfectly
listIList.Add(10);
}
В обох випадках, коли я намагаюся додати нове значення, мій компілятор не видає мені помилок, але, очевидно, метод, який виставляє мій масив як IList<T>
помилку, дає помилку виконання, коли я намагаюся щось додати до нього. Тож люди, які не знають, що відбувається в моєму методі, і їм потрібно додати значення, змушені спочатку скопіювати мій IList
у a, List
щоб мати змогу додавати значення без ризику помилок. Звичайно, вони можуть зробити перевірку типу, щоб побачити, чи мають вони справу з a List
або an Array
, але якщо вони цього не роблять, і вони хочуть додати елементи до колекції, у них немає іншого вибору для копіювання в IList
a List
, навіть якщо це вже єList
. Чи не слід масив ніколи виставляти як IList
?
Ще одне моє занепокоєння ґрунтується на прийнятій відповіді на пов'язане запитання (наголос на моєму):
Якщо ви виставляєте свій клас за допомогою бібліотеки, якою користуватимуться інші, ви, як правило, хочете виставити його за допомогою інтерфейсів, а не конкретних реалізацій. Це допоможе, якщо ви вирішите змінити реалізацію свого класу пізніше, щоб використовувати інший конкретний клас. У цьому випадку користувачам вашої бібліотеки не потрібно буде оновлювати свій код, оскільки інтерфейс не змінюється.
Якщо ви просто використовуєте його внутрішньо, вам може бути все одно, і використання списку може бути нормальним.
Уявіть, хтось насправді використовував моє, IList<T>
отримане від мого ExposeListIlist()
методу, просто для додавання / видалення значень. Все працює нормально. Але тепер, як пропонується відповідь, оскільки повернення інтерфейсу є більш гнучким, я повертаю масив замість Списку (з моєї сторони не проблема!), Тоді вони чекають задоволення ...
TLDR:
1) Оголення інтерфейсу спричиняє непотрібні ролі? Це не має значення?
2) Іноді, якщо користувачі бібліотеки не використовують прив'язку, їх код може зламатися, коли ви зміните метод, хоча метод залишається цілком чудовим.
Я, напевно, надмірно обдумую це, але я не отримую загального консенсусу, що повернення інтерфейсу має бути кращим, ніж повернення реалізації.
IEnumerable<T>
і ви скомпілюєте безпеку часу. Ви все ще можете використовувати всі методи розширення LINQ, які зазвичай намагаються оптимізувати продуктивність, приводячи її до певного типу (наприклад,ICollection<T>
використовуватиCount
властивість замість перерахування).