Při psaní frameworků je vždy nutné najít kompromis mezi množstvím funkcí, které nabízí, a velikostí, kterou zabírá. Ne jinak tomu je i v případě .NET Micro Frameworku, kde jsou navíc nároky na velikost velice tvrdé. Proto některé funkce, které C# běžně umožňuje, nejsou bohužel k dispozici. Občas však stačí k obejití omezení jen malý trik (ne, generics nejsou ten případ). Myslel jsem, že by mohlo přijít vhod mít to vše pohromadě.
Nejdřív, tabulka.
People seem to like tables. —Raymond
Po několika pokusech jsem se rozhodl anglické termíny nepřekládat, kdyby někdo měl pocit, že zná super překlady, tak dejte vědět (strojový překlad v českém .NET Frameworku mě příliš neoslnil).
V tabulce je shluk několika funkcí a vymožeností. Některé jsou jen syntaktický cumel, jiné hluboké změny v CLR a některé zase potřebují podporu frameworku. Všechny položky ale vyžadují, aby C# kompilátor udělal nějakou práci navíc nebo podporoval nová klíčová slova.
Pokud zjistím něbo někdo zjistíte jak realizovat některou z červených položek, tabulku aktualizuji – dejte mi vědět.
Ti, jenž si pamatují Visual Studio .NET, nejspíš vědí že novinek v CLR 2.0 a C# 2.0 nebylo málo. Samozřejmě tou nejdůležitější a nejrozsáhlejší bylo zavedení generických typů, ale i jiné novinky se dnes staly samozřejmostí. Naštěstí z nich většina funguje bez domlouvání:
Účel: Možnost rozdělit třídu, strukturu nebo interface do několika souborů. Podrobnosti
Příklad:
Způsobí: Kompilátor spojí všechny patřičné soubory do jedné třídy/struktury/interface.
Stav: Funguje bez problémů.
Účel: Třídy, které nemohou být instanciovány ani zděděny. Obsahují pouze statické členy a nemají žádný instanční konstruktor. Podrobnosti
Způsobí: Že kompilátor nedodá výchozí instanční konstruktor.
Účel: Rozlišit mezi typy se stejným názvem, a možnost odkázat se na začátek jmenného prostoru. Podrobnosti
Způsobí: Pomáhá kompilátoru s rozlišením jmenných prostorů.
Stav: Funguje bez problémů, ale extern alias vyžaduje speciální parametry při kompilaci, takže není v běžných případech k dispozici.
Účel: Umožnit vlastnostem rozdílný přístup pro čtení a pro zápis. Podrobnosti
Způsobí: Že kompilátor aplikuje uvedené modifikátory na příslušné set_ a get_ metody.
Účel: Krátké metody beze jména. Podrobnosti
Způsobí: Že kopmilátor vygeneruje standardní metodu se jménem dle svého uvážení.
Účel: Nevytvářet instanci delegáta.
Způsobí: Že si kompilátor dovodí potřebný typ delegáta a převede to na kód výše.
Účel: Vyšší flexibilita při předávání delegátů. Podrobnosti
Způsobí: Že si kompilátor nestěžuje pokud lze parametry implicitně zkonvertovat.
Účel: Umožnit odkázat se na proměnnou mimo tělo anonymní metody.
Způsobí: Že kompilátor vygeneruje vnořenou třídu pro uložení proměnné. To vás může dostat do potíží, viz:
for (int i = 0; i < 10; i++) { Dispatcher.BeginInvoke(new System.Threading.ThreadStart(delegate { System.Diagnostics.Debug.Print("i = " + i); })); } A teď: Kompilátor vygeneruje třídu pro uložení probměnné. Takže výstup bude 10, 10, 10, 10, 10, 10, 10, 10, 10, 10. Abychom dosáhli svého, musíme kompilátor přesvědčit, že se promměná nezmění už nikdy více, např.: for (int i = 0; i < 10; i++) { int iFixed = i; Dispatcher.BeginInvoke(new System.Threading.ThreadStart(delegate { System.Diagnostics.Debug.Print("i = " + iFixed); })); } V tomto případě dostaneme očekávaných 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
Účel: Zjednodušení implementace IEnumerable objektů. Podrobnosti
Způsobí: Že kompilátor vygeneruje vnořenou třídu s konečným automatem.
Pro dalších podrobnosti a příklady výše uvedených funkcí stojí za shlédnutí (anglický) článek v MSDN Magazínu Create Elegant Code With Anonymous Methods, Iterators, And Partial Classes.
Účel: Typová bezpečnost, znovupoužití kódu a zvýšení výkonu. Podrobnosti
Způsobí: Na rozdíl od všech předchozích funkcí, toto je zásadní změna v CLR. Nahrazení konkrétních typů probíhá za běhu, nikoliv při kompilaci. Nejen proto generické typy nejsou C++ šablony.
Stav: Momentálně není v .NET Micro Frameworku k dispozici kvůli prostorovým nárokům.
Účel: Umožnit jednoduchým datovým typům mít hodnotu "nedefinováno". Podrobnosti
Způsobí: Nahrazení příslušným generickým typem System.Nullable<T>.
Stav: Momentálně není v .NET Micro Frameworku k dispozici, jelikož vyžaduje genercké typy.
Účel: Zjednodušit kód. Podrobnosti
Způsobí: a ?? b je nahraženo a != null ? a : (b).
Vlajkovou lodí C# 3.0 byl LINQ (Language-Integrated Query) a téměř všechny nové funkce jazyka byly zavedeny, aby LINQ umožnily nebo udělaly hezky vypadajícím. C# 3.0 používá CLR 2.0, tedy žádné změny pro .NET Micro Framework.
Způsobí: Že kompilátor vygeneruje potřebnou proměnnou automaticky, pojmenovanou dle svého uvážění.
Účel: Umožnit vytváření anonymních typů, zjednodušit kód. Podrobnosti
Způsobí: Že kompilátor vloží kód, který vytvoří instanci daného typu, nastaví požadované proměnné nebo vlastnosti a přiřadií ji deklarované proměnné.
Způsobí: Že kompilátor vloží kód, který vytvoří instanci daného typu, zavolá její metodu Add, a přiřadí ji deklarované proměnné.
Stav: Funguje bez problémů. Vytvářený objekt musí samozřejmě mít veřejnou metodu Add s jediným parametrem, veřejný konstruktor bez parametru, a, není mi úplně jasné proč, dědit System.Collections.IEnumerable, stačí neimplementovaný.
Účel: Umožnit ukládání anonymních typů, zjednodušit psaní kódu. Podrobnosti
Způsobí: Že kompilátor doplní správný typ. Během kompilace, nikoliv za běhu.
Způsobí: Že kompilátor doplní správný typ.
Účel: Přidat funkcionalitu třídě, kterou nevlastníme, s jednoduchou syntaxí. Podrobnosti
Způsobí: Že kompilátor nahradí extenzní metody za volání příslušných statických metod.
Stav: Funguje, ale kompilátor potřebuje označit extenzní metody a jejich třídu atributem System.Runtime.CompilerServices.ExtensionAttribute, který není obsažen v standardních knihovnách .NET Micro Frameworku. Není však těžké jej napsat:
using System; namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)] public sealed class ExtensionAttribute : Attribute { } }
Účel: Snadná syntaxe pro krátké anonymní metody, v dotazech umožňuje filtrování, výběr, řazení... Podrobnosti
Způsobí: Zacházení jako s běžnými anonymními metodami.
Stav: Funguje, ale musí se deklarovat delegáti. Typy System.Func<> nejsou kvůli potřebě generics k dispozici.
Účel: Uložení postupu vyhodnocování funkcí, umožňuje optimalizaci dotazů. Podrobnosti
Způsobí: Že kompilátor vygeneruje hromadu kódu na postavení stromu pomocí typů v System.Linq.Expressions.
Stav: Není k dispozici kvůli potřebě generics (a všech Expressions tříd). Negenerické verze lze nadeklarovat, ale už ne přesvědčit kompilátor, aby je použil místo generických.
Účel: Zahrnout dotazy v přirozeném jazyce do kódu. Podrobnosti
Způsobí: Že kompilátor dotaz převede na extenzní metody a lambda funkce, resp. volání příslušných statických metod a anonymních funkcí.
Stav: Funguje, ale musí se napsat všechny extenzní metody. Příklad viz blog Mobile Software Engineering.
Účel: Zabalit několik vlastností pro čtení bez potřeby deklarovat typ, umožňuje selekci v dotazech. Podrobnosti
Způsobí: Že kompilátor vygeneruje potřebnou třídu, vlastnosti jsou jen pro čtení (pomocí readonly proměnných).
Stav: Není k dispozici, bohužel stávající kompilátor používá v generovaných třídách generics (a System.Text.StringBuilder).
Účel: Umožnit přegenerovat kód bez ovlivnění kódu dopsaného vývojářem, používá se v LINQ to SQL designeru. Podrobnosti
Způsobí: Že kompilátor metody spojí, pokud implementace existuje, v opačném případě ji zcela odstraní včetně všech volání.
Pro čtvrtou verzi si myslím že je hlavním tahákem Dynamic Language Runtime, která samozřejmě v .NET Micro Frameworku není. Ve velkém .NET Framework je potřeba na podporu některých dynaamických jazyků, jako např. IronPython, a ke zjednodušení komunikace s COM objekty. Ani jedno z toho není v případě .NET Micro Frameworku potřeba.
Účel: Obejít statickou kontrolů typů a řešit vše až za běhu. Podrobnosti
Způsobí: Vygenerování vnořené třídy a manipulace objektu probíhá přes binder.
Stav: Dynamic Language Runtime není v .NET Micro Framework k dispozici (a generovaný kód používá generické typy).
Účel: Odstranit nutnost si pamatovat nebo vyhledávat pořadí parametrů. Podrobnosti
Způsobí: Že kompilátor přeuspořádá parametry do správného pořadí.
Účel: Stanovit výchozí hodnoty parametrů, které pak mohou být vynechány. Podrobnosti
Způsobí: C# kompilátor nahrazuje chybějící parametry jejich výchozími hodnotami. Při kompilaci. To znamená, že pokud je výchozí hodnota změněna, volající kód není pozměněn dokud se nepřekompiluje.
Stav: Funguje bez problémů. Atribute System.Runtime.InteropServices.OptionalAttribute a DefaultParameterValueAttribute nejsou nutné, jedná se o funkci CLR.
Účel: Umožnit implicitní konverzi generických typů. Podrobnosti
Způsobí: Že si kompilátor nestěžuje a runtime při práci s generics zohlední implicitní konverzi typů parametrů.
Stav: Generics nejsou k dispozici.
Toť prozatím vše.