.NET 4.5Byly přidány dvě nová rozhraní pro sbírky, IReadOnlyList a IReadOnlyDictionary. Ačkoliv se tato rozhraní na první pohled mohou zdát nudně, odhalují poměrně složité příběhy o zpětné kompatibilitě, interoperabilitě a roli spoluproměnlivosti.
IReadOnlyList a IReadOnlyDictionary jsou dvě rozhraní, která vývojáři .NET vždy chtěli mít. Kromě určité symetrie (na rozdíl od zapisovatelných rozhraní) by mělo rozhraní pouze pro čtení eliminovat implementaci metod, které vyhazují pouze výjimku NotSupportedException a nic nedělají. To vše nebylo dokončeno kvůli časovým omezením.
Další příležitost je tu. NET 2.0. To umožňuje Microsoftu stáhnout kolekce se slabým typem a nahradit je silně typovanými kolekcemi peer. Tým základní knihovny[1] však opět promarnil příležitost poskytnout pouze pro čtení, jak napsal Kit George,
Protože chceme poskytnout výchozí implementaci pro problém, o kterém mluvíte s Joem, místo aby bylo poskytnuto rozhraní, poskytujeme základní třídu ReadOnlyCollectionBase. Nicméně chápu, proč se lidé zdráhají ho použít, protože není silný typ. Ale s příchodem generik máme nyní také ReadOnlyCollection<T>, takže nejen získáte stejnou funkčnost, ale také silný typ: skvělé!
Protože ReadOnlyCollection <T>není uzavřená třída, můžete si v případě potřeby napsat vlastní kolekci plnou rychlostí. Protože tyto kolekce, které jsme vytvořili pro tento účel, jsou přizpůsobitelné obecným potřebám, neplánujeme zavádět rozhraní pro stejný koncept. Krzysztof Cwalina také vyjádřil svůj názor na toto téma,
Ať už to zní překvapivě nebo ne, IList a IList <T>jsou dvě rozhraní, která hodláme použít pro kolekce pouze pro čtení. Oba mají booleovskou vlastnost IsReadOnly, která by měla vrátit true, když kolekce pouze pro čtení implementuje tuto vlastnost. Důvod, proč nechceme přidávat čistě čtecí rozhraní, je ten, že podle nás přidává příliš mnoho zbytečné složitosti do základní knihovny. Všimněte si, že z hlediska složitosti máme na mysli jak toto nové rozhraní, tak jeho uživatele.
Domníváme se, že pokud návrhář API neřeší kontrolu vlastnosti IsReadOnly za běhu a výjimek, které může vyvolat, je v tomto případě v pořádku použít rozhraní IList; Pokud jsou ochotni poskytnout opravdu čisté vlastní API najednou, pak by v tomto případě měli ukázat implementaci rozhraní IList a publikovat na míru přizpůsobené API pouze pro čtení. To je typické pro kolekce vystavené objektovému modelu. Ačkoliv si vývojáři na tuto situaci stěžovali, nové možnosti, které generika nabízejí, daleko převyšují tento klíčový problém a problém je v . NET 4 byl dříve většinou ignorován. Toto rozhodnutí však vyvolalo i určité reakce, o kterých budeme mluvit později.
S vnitřkem. Do běhu byla přidána vzrušující nová funkce v .NET 4. V dřívější verzi. .NET, když se rozhraní stanou typy, jsou tato rozhraní příliš omezená. Například i když zákazník dědí od osoby, není možné předat objekt typu IEnumerable <Customer>jako parametr funkci typu IEnumerable<Person>. S přidáním kovariantní podpory bylo toto omezení částečně zrušeno.
Říkáme "částečně", protože v některých případech by lidé měli používat rozhraní s bohatým API najednou, místo aby používali IEnumerable rozhraní. I když rozhraní IList není kovariantní, rozhraní pouze pro čtení by mělo být. Bohužel, . Tým pro základní knihovnu .NET se opět rozhodl tuto chybu neřešit.
Pak příchod WinRT a návrat COM změnil všechno. Interoperabilita COM byla kdysi technologií, kterou vývojáři používali, když neměli jinou možnost, ale dnes se stala . Základní kámen .NET programování. A protože WinRT zpřístupňuje IVectorView <T>a IMapView<K, V> rozhraní tedy. .NET je také nutné upravit.
Jednou zajímavostí programu WinRT je oznámení odlišných, ale podobných API pro každou vývojovou platformu. Jak už možná víte, všechny názvy metod jsou reprezentovány camelCased [2], zatímco vývojáři v C++ a .NET používají názvy metod jako PascalCased [3]. Další výraznější změnou je automatické mapování mezi rozhraními C++ a .NET. Proto. Vývojáři .NET nemusí řešit jmenný prostor Windows.Foundation.Collections, stačí pokračovat v používání jmenného prostoru System.Collections.Generic. Rozhraní IVectorView <T>a IMapView<K, V> budou během běhu převedena na rozhraní IReadOnlyList <T>a IReadOnlyDictionary<TKey, TValue> v uvedeném pořadí.
Stojí za zmínku, že tyto názvy rozhraní v C++/WinRT jsou do určité míry přesnější. Tato rozhraní slouží k reprezentaci některých pohledů na kolekci, ale rozhraní nezaručuje, že samotná kolekce je neměnná. Dokonce i mezi těmi, kteří mají zkušenosti. Častou chybou mezi vývojáři .NET je předpokládat, že typ ReadOnlyCollection je kopií neměnné kolekce, ale ve skutečnosti jde pouze o obal aktivní kolekce (viz příspěvek Andrewa Arnotta se stejným názvem pro více informací o kolekcích pouze pro čtení, zmrazených a neměnných).
Ačkoli rozhraní IList <T>má všechny stejné členy jako rozhraní IReadOnlyList <T>a všechny seznamy typu IList <T>lze reprezentovat jako seznamy pouze pro čtení, IList <T>nedědí z IReadOnlyList<T>, což může být zajímavé se dozvědět. Immo Landwerth vysvětlil,
Důvod, proč to funguje, je ten, že tato rozhraní pouze pro čtení jsou čistě podmnožinami rozhraní pro čtení a zápis, což se zdá být rozumným předpokladem. Bohužel tento předpoklad neodpovídá realitě, protože každá metoda na každém rozhraní na úrovni metadat má svůj vlastní slot (což umožňuje explicitní implementace rozhraní). Jinými slovy, jedinou šancí zavést rozhraní pouze pro čtení jako základní třídu proměnné je vrátit se k . NET 2.0, tedy kdy byly původně navrženy. Jakmile je plně rozvinutý, jedinou změnou, kterou může provést, je přidání kovariantních a/nebo invertorových značek (označených jako "in" a "out" ve VB a C#).
Na otázku, proč neexistuje rozhraní IReadOnlyCollection<T>, Immo odpověděl,
Tento návrh jsme zvažovali, ale cítili jsme, že přidání typu, který poskytuje pouze atribut Count, by základní knihovně příliš nepřidalo. V týmu základních knihoven věříme, že pokud API začíná na minus 1000, pak ani poskytnutí nějaké hodnoty nestačí k tomu, aby bylo přidáno. Důvod pro přidání nových API zahrnuje také náklady, například vývojáři budou mít na výběr více konceptů. Nejprve jsme si mysleli, že přidání tohoto typu pomůže kódu lépe fungovat v určitých situacích, kdy chcete jen získat počet a pak s ním udělat něco zajímavého. Například hromadné přidávání do existující sbírky. V těchto případech jsme však doporučovali používat pouze rozhraní IEnumerable<T>, a <T>ve speciálním případě mít instanci, která implementuje ICollection rozhraní. Protože všechny naše vestavěné typy kolekcí tuto rozhraní implementovaly, nedošlo v těchto nejběžnějších scénářích k žádnému zvýšení výkonu. Mimochodem, <T>metoda rozšíření Count() pro IEnumerable to také dokáže. Tato nová rozhraní jsou dostupná pro . NET 4.5 a . NET for Windows 8。
Poznámky k překladu
[1] Knihovna základní třídy, zkráceně BCL. Pro více informací o knihovně základních tříd se prosím zapojte do MSDN.
[2] velbloudí názvosloví, nomenklatura hrbů, také známá jako spodní velbloudí pouzdro. Formát je takový, že první slovo začíná malým písmenem; První písmeno druhého slova je napsáno s velkým písmenem, například: firstName, lastName.
[3] PascalCased, Pascalova nomenklatura, také známá jako případ horního velblouda. Formát je takový, že první písmeno každého slova je psáno s velkým písmenem, například: FirstName, LastName, CamelCase. |