.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#).
Когато го попитаха защо няма интерфейс IReadOnlyCollection<T>, Иммо отговори,
Обмислихме този дизайн, но смятахме, че добавянето на тип, който предоставя само атрибута Count, няма да добави голяма стойност към основната библиотека. В екипа за базова библиотека вярваме, че ако API започва от минус 1000, дори предоставянето на някаква стойност не е достатъчно, за да оправдае добавянето му. Причината за добавяне на нови API включва и цена, например разработчиците ще имат повече концепции за избор. Първоначално мислехме, че добавянето на този тип ще накара кода да работи по-добре в определени ситуации, когато просто искаш да вземеш броя и после да направиш нещо интересно с него. Например, масово добавяне към съществуваща колекция. Въпреки това, в тези ситуации сме насърчили хората да използват само <T>интерфейса IEnumerable, а <T>в специалния случай на инстанция, която реализира интерфейса ICollection. Тъй като всички наши вградени типове колекция имплементираха този интерфейс, няма никакво подобрение в производителността в тези най-често срещани сценарии. Между другото, <T>методът за разширение Count() за IEnumerable също може да направи това. Тези нови интерфейси са налични за . NET 4.5 и . NET for Windows 8。
Бележки към превода
[1] Библиотека на базовия клас, съкратено BCL. За повече информация относно библиотеката на базовия клас, моля, участвайте в MSDN.
[2] CamelCased, наименование на гърбица, известно още като долен камилски корпус. Форматът е, че първата дума започва с малка буква; Първата буква на втората дума се изписва с главна буква, например: firstName, lastName.
[3] PascalCased, Pascal номенклатура, известна още като горен камилски корпус. Форматът е, че първата буква на всяка дума се пише с главна буква, например: FirstName, LastName, CamelCase. |