.NET 4.5Додано два нові інтерфейси колекції — IReadOnlyList та IReadOnlyDictionary. Хоча ці інтерфейси можуть здаватися буденними на перший погляд, вони відкривають досить складні історії про зворотну сумісність, сумісність і роль комутації.
IReadOnlyList та IReadOnlyDictionary — це два інтерфейси, які розробники .NET завжди хотіли мати. Окрім забезпечення певної симетрії (на відміну від переписуваних інтерфейсів), інтерфейс лише для читання повинен усувати реалізацію методів, які лише викидають виняток NotSupportedException і нічого не роблять. Усе це не було завершено через обмеження часу.
Наступна можливість з'явилася. NET 2.0. Це дозволяє Microsoft відмовлятися від слабо типізованих колекцій і замінювати їх сильно типізованими однотипними колекціями. Однак команда базової бібліотеки[1] знову втратила можливість надати список лише для читання, як писав Кіт Джордж,
Оскільки ми маємо намір надати стандартну реалізацію для задачі, про яку ви говорите, замість інтерфейсу, ми надаємо базовий клас ReadOnlyCollectionBase. Однак я розумію, чому люди неохоче його використовують, адже це не сильний тип. Але з появою генериків ми також маємо <T>ReadOnlyCollection, тож ви отримуєте не лише ту ж функціональність, а й сильний шрифт: чудово!
Оскільки ReadOnlyCollection <T>не є запечатаним класом, ви можете писати власну колекцію на повній швидкості, якщо потрібно. Оскільки ці колекції, які ми створили для цього, адаптуються до загальних потреб, ми не плануємо вводити інтерфейси для цієї ж концепції. Кшиштоф Цваліна також висловив свою думку з цього приводу,
Чи звучить це дивно, чи ні, IList <T>і IList — це два інтерфейси, які ми плануємо використовувати для колекцій лише для читання. Обидва мають булеву властивість IsReadOnly, яка має повертати true, коли колекція лише для читання реалізує цю властивість. Причина, чому ми не хочемо додавати повністю читальний інтерфейс, полягає в тому, що вважаємо, що це додає надмірної зайвої складності базовій бібліотеці. Зверніть увагу, що з точки зору складності ми маємо на увазі як цей новий інтерфейс, так і його споживачів.
Ми вважаємо, що якщо дизайнер API не звертає уваги на перевірку властивості IsReadOnly під час виконання та про можливі винятки, то в цьому випадку можна використовувати інтерфейс IList; Якщо вони готові надати дійсно чистий кастомний API за один раз, то в цьому випадку їм слід показати реалізацію інтерфейсу IList і опублікувати індивідуальний API лише для читання. Останнє типове для колекцій, відкритих із об'єктної моделі. Хоча розробники скаржилися на цю ситуацію, нові можливості, які дають генерики, значно переважають цю сутність, і проблема полягає в . NET 4 раніше здебільшого ігнорували. Однак це рішення також викликало певні реакції, про які ми поговоримо пізніше.
З входом. У форматі виконання додано захоплюючу нову функцію в .NET 4. У більш ранній версії. .NET, коли інтерфейси стають типами, ці інтерфейси надто обмежені. Наприклад, навіть якщо Customer успадковує від Person, неможливо передати об'єкт типу <Customer>IEnumerable як параметр функції типу IEnumerable<Person>. З додаванням коваріантної підтримки це обмеження частково було знято.
Ми кажемо «частково», бо в деяких випадках людям слід одночасно використовувати інтерфейс із багатим API, а не IEnumerable. Навіть якщо інтерфейс IList не є коваріантним, інтерфейс списку лише для читання має бути таким. На жаль, . Команда базової бібліотеки .NET знову вирішила не вирішувати цю помилку.
Потім поява WinRT і повернення COM змінили все. Колись інтероперабельність COM була технологією, яку розробники використовували, коли не мали іншого вибору, але зараз вона стала . Наріжний камінь програмування .NET. І оскільки WinRT відкриває <T>інтерфейси IVectorView та IMapView<K, V> .NET також потрібно відповідно коригувати.
Однією з цікавих особливостей програми WinRT є анонс про різні, але схожі API для кожної платформи розробки. Як ви, мабуть, вже знаєте, всі імена методів представлені camelCased [2], тоді як розробники C++ і .NET розглядають назви методів як PascalCased [3]. Ще однією більш суттєвою зміною є автоматичне відображення між інтерфейсами C++ і .NET. Отже. Розробникам .NET не потрібно мати справу з простором імен Windows.Foundation.Collections, вони просто продовжують користуватися простором імен System.Collections.Generic. <T>Інтерфейси IVectorView та IMapView<K, V> будуть конвертовані у час виконання у <T>інтерфейси IReadOnlyList та інтерфейси IReadOnlyDictionary<TKey, TValue> відповідно.
Варто зазначити, що назви інтерфейсів у C++/WinRT певною мірою є точнішими. Ці інтерфейси використовуються для представлення деяких зображень колекції, але інтерфейс не гарантує незмінність самої колекції. Навіть серед тих, хто має досвід. Поширеною помилкою серед розробників .NET є припущення, що тип ReadOnlyCollection є копією незмінної колекції, але насправді це лише обгортка для активної колекції (див. допис Ендрю Арнотта з такою ж назвою для отримання додаткової інформації про колекції лише для читання, заморожені та незмінні колекції).
Хоча <T>інтерфейс IList має всі ті ж члени, що й інтерфейс IReadOnlyList<T>, і всі <T>списки типу IList можуть бути представлені як списки лише для читання, IList <T>не успадковує від IReadOnlyList<T>, що може бути цікаво дізнатися. Іммо Ландверт пояснив,
Причина, чому це працює, полягає в тому, що ці інтерфейси лише для читання є чистими підмножинами інтерфейсів читання-запису, що здається розумним припущенням. На жаль, це припущення не відповідає реальності, оскільки кожен метод на кожному інтерфейсі на рівні метаданих має власний слот (що дозволяє реалізації явних інтерфейсів працювати). Іншими словами, єдиний шанс ввести інтерфейс лише для читання як базовий клас змінного — це повернутися до . NET 2.0, тобто коли вони були вперше задумані. Після повного впровадження єдина зміна — додати коваріантні та/або інверторні маркери (позначених як «in» і «out» у VB та C#).
На запитання, чому немає <T>інтерфейсу IReadOnlyCollection, Іммо відповів:
Ми розглядали таку конструкцію, але вважали, що додавання типу, який надає лише атрибут Count, не додасть великої цінності базовій бібліотеці. У команді базової бібліотеки ми вважаємо, що якщо API починається з мінус 1000, то навіть надання певної цінності недостатнє для виправдання його додавання. Мотивація додавання нових API також включає вартість — наприклад, розробники матимуть більше концепцій на вибір. Спочатку ми думали, що додавання такого типу покращить роботу коду в певних ситуаціях, коли потрібно просто отримати підрахунок і зробити щось цікаве. Наприклад, масове додавання до існуючої колекції. Однак у таких ситуаціях ми заохочували людей використовувати лише <T>інтерфейс IEnumerable, а <T>у особливому випадку — мати екземпляр, який реалізує інтерфейс ICollection. Оскільки всі наші вбудовані типи колекцій реалізували цей інтерфейс, у цих найпоширеніших сценаріях не було приросту продуктивності. До речі, <T>метод розширення Count() для IEnumerable також може це робити. Ці нові інтерфейси доступні для . NET 4.5 і . NET for Windows 8。
Примітки до перекладу
[1] Бібліотека базового класу, скорочено BCL. Для отримання додаткової інформації про бібліотеку базового класу, будь ласка, беріть участь у MSDN.
[2] верблюжий корпус, номенклатура «горб», також відомий як нижній верблюжий корпус. Формат такий: перше слово починається з малої літери; Перша літера другого слова пишеться з великої літери, наприклад: FirstName, LastName.
[3] PascalCased, номенклатура Паскаля, також відома як верхній верблюжий корпус. Формат такий: перша літера кожного слова пишеться з великої літери, наприклад: FirstName, LastName, CamelCase. |