Department of InformatiX
Microsoft .NET Micro Framework Tools & Resources

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

Funkce Požadovaný C# kompilátor .NET Micro Framework Požadované funkce frameworku
Partial classes 2.0 ano
Static classes 2.0 ano
Aliases 2.0 ano
Property access modifiers 2.0 ano
Anonymous methods 2.0 ano
Delegate inference 2.0 ano
Variable capturing 2.0 ano
Yields 2.0 ano IEnumerable, IEnumerator
Generics 2.0 ne generics
Nullables 2.0 ne generics, Nullable<>
Null coalescing operator 2.0 ano
Funkce Požadovaný C# kompilátor .NET Micro Framework Požadované funkce frameworku
Auto-implemented properties3.0 ano
Object initializers 3.0 ano
Collection initializers 3.0 ano IEnumerable
Implicitly typed local variables3.0 ano
Implicitly typed arrays 3.0 ano
Extension methods 3.0 ANO ExtensionAttribute
Lambda epressions 3.0 ANO (Func<>)
Expression trees 3.0 ne generics, Expression<>
Query expressions 3.0 ANO IEnumerable, Expressions.*
Anonymous types 3.0 ne generics, StringBuilder
Partial methods 3.0 ano
Funkce Požadovaný C# kompilátor .NET Micro Framework Požadované funkce frameworku
Dynamic lookup 4.0 ne generics, CallSite, Binder
Named parameters 4.0 ano
Optional parameters 4.0 ano
Variance in generic types 4.0 ne generics

 

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.

Novinky v C# 2.0

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í:

Partial Classes

Účel: Možnost rozdělit třídu, strukturu nebo interface do několika souborů. Podrobnosti

Příklad:

// Banán.Bů.cs public partial class Banán { ... // Část bů } // Banán.Fů.cs public partial class Banán { ... // Část fů }

Způsobí: Kompilátor spojí všechny patřičné soubory do jedné třídy/struktury/interface.

Stav: Funguje bez problémů.

Static Classes

Účel: Třídy, které nemohou být instanciovány ani zděděny. Obsahují pouze statické členy a nemají žádný instanční konstruktor. Podrobnosti

Příklad:

public static class Math { ... // statické metody, konstanty, atd... }

Způsobí: Že kompilátor nedodá výchozí instanční konstruktor.

Stav: Funguje bez problémů.

Aliases

Účel: Rozlišit mezi typy se stejným názvem, a možnost odkázat se na začátek jmenného prostoru. Podrobnosti

Příklad:

extern alias Fů; extern alias Bů; ... public void DělejVěci() { Fů::Třída.ŘekniNazdar(); // umložňuje použít identicky jmenující se typy Bů::Třída.ŘekniNazdar(); global::System.Diagnostics.Debug.Print("Uf."); // zajistí použití správného typu ::System.Diagnostics.Debug.Print("Uf."); // ekvivalentní s global:: }

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.

Property Access Modifiers

Účel: Umožnit vlastnostem rozdílný přístup pro čtení a pro zápis. Podrobnosti

Příklad:

public string Jméno { get { ... } private set { ... } }

Způsobí: Že kompilátor aplikuje uvedené modifikátory na příslušné set_ a get_ metody.

Stav: Funguje bez problémů.

Anonymous Methods

Účel: Krátké metody beze jména. Podrobnosti

Příklad:

// public delegate void EventHandler(object sender, EventArgs e); Microsoft.SPOT.Application.Startup += new Microsoft.SPOT.EventHandler( delegate(object sender, EventArgs e) { ... });

Způsobí: Že kopmilátor vygeneruje standardní metodu se jménem dle svého uvážení.

Stav: Funguje bez problémů.

Delegate Inference

Účel: Nevytvářet instanci delegáta.

Příklad:

// public delegate void EventHandler(object sender, EventArgs e); Microsoft.SPOT.Application.Startup += delegate(object sender, EventArgs e) { ... }; // Ale také (méně známé): Microsoft.SPOT.Application.Startup += MyStartupHandler; ... private void MyStartupHandler(object sender, EventArgs e) { ... }

Způsobí: Že si kompilátor dovodí potřebný typ delegáta a převede to na kód výše.

Stav: Funguje bez problémů.

Delegate Covariance and Contra-variance

Účel: Vyšší flexibilita při předávání delegátů. Podrobnosti

Příklad:

// public delegate void InsertEventHandler(object sender, MediaEventArgs e); Microsoft.SPOT.IO.RemovableMedia.Insert += delegate(object sender, EventArgs e) { ... }; // Ale také: Microsoft.SPOT.IO.RemovableMedia.Insert += delegate { ... }; // ekvivalentní s delegate(object, object)

Způsobí: Že si kompilátor nestěžuje pokud lze parametry implicitně zkonvertovat.

Stav: Funguje bez problémů.

Variable capturing

Účel: Umožnit odkázat se na proměnnou mimo tělo anonymní metody.

Příklad:

private void NastaveTextLabelu(string text) { if (MůjLabel.CheckAccess()) MůjLabel.Text = text; else MůjLabel.Dispatcher.BeginInvoke(new System.Threading.ThreadStart(delegate { MůjLabel.Text = text; })); }

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.

Stav: Funguje bez problémů.

Yields

Účel: Zjednodušení implementace IEnumerable objektů. Podrobnosti

Příklad:

static System.Collections.IEnumerable NekonečnáPosloupnostNáhodnýchČísel { get { System.Random generator = new System.Random(); while (true) yield return generator.Next(); } }

Způsobí: Že kompilátor vygeneruje vnořenou třídu s konečným automatem.

Stav: Funguje bez problémů.

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.

Generics

Účel: Typová bezpečnost, znovupoužití kódu a zvýšení výkonu. Podrobnosti

Příklad:

public class Complex<T> { public T Real; public T Imaginary; }

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.

Nullables

Účel: Umožnit jednoduchým datovým typům mít hodnotu "nedefinováno". Podrobnosti

Příklad:

int? hodnota = null;

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.

Null coalescing operator

Účel: Zjednodušit kód. Podrobnosti

Příklad:

string parametr = uživatelovaHodnota ?? "výchozí hodnota";

Způsobí: a ?? b je nahraženo a != null ? a : (b).

Stav: Funguje bez problémů.

Novinky v C# 3.0

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.

Auto-Implemented Properties

Účel: Zjednodušit kód. Podrobnosti

Příklad:

public string Jméno { get; set; }

Způsobí: Že kompilátor vygeneruje potřebnou proměnnou automaticky, pojmenovanou dle svého uvážění.

Stav: Funguje bez problémů.

Object Initializers

Účel: Umožnit vytváření anonymních typů, zjednodušit kód. Podrobnosti

Příklad:

Microsoft.SPOT.DispatcherTimer timer = new Microsoft.SPOT.DispatcherTimer { Interval = new System.TimeSpan(0, 0, 1), IsEnabled = true }; // konstruktory s parametry jsou rovněž podporovány: Microsoft.SPOT.DispatcherTimer timer = new Microsoft.SPOT.DispatcherTimer(Dispatcher) { Interval = new System.TimeSpan(0, 0, 1), IsEnabled = true };

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é.

Stav: Funguje bez problémů.

Collection Initializers

Účel: Umožnit vytváření anonymních typů, zjednodušit kód. Podrobnosti

Příklad:

System.Collections.ArrayList seznam = new System.Collections.ArrayList { 25, 3, 85, "MF", null };

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ý.

Implicitly Typed Local Variables

Účel: Umožnit ukládání anonymních typů, zjednodušit psaní kódu. Podrobnosti

Příklad:

var mf = "Small is beautiful.";

Způsobí: Že kompilátor doplní správný typ. Během kompilace, nikoliv za běhu.

Stav: Funguje bez problémů.

Implicitly Typed Arrays

Účel: Umožnit ukládání anonymních typů, zjednodušit psaní kódu. Podrobnosti

Příklad:

object pole = new[] { "alfa", "beta" }; // mimochodem toto funguje již od C# 1.0 (array initializer): string[] array = { "alfa", "beta" };

Způsobí: Že kompilátor doplní správný typ.

Stav: Funguje bez problémů.

Extension Methods

Účel: Přidat funkcionalitu třídě, kterou nevlastníme, s jednoduchou syntaxí. Podrobnosti

Příklad:

static class RandomExtensions { public static byte NextByte(this System.Random random) { return (byte)random.Next(byte.MaxValue); } } ... System.Random generátor = new System.Random(); byte náhodnýBajt = generátor.NextByte(); // ekvivalentní s RandomExtensions.NextByte(generator);

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 { } }

Lambda Expressions

Účel: Snadná syntaxe pro krátké anonymní metody, v dotazech umožňuje filtrování, výběr, řazení... Podrobnosti

Příklad:

// parametry a návratová hodnota delegate bool Filtr(int x); ... Filtr jeNula = a => a == 0; bool dvacetpětJeNula = jeNula(25); // žádné parametry delegate int Konstanta(); ... Konstanta pořádŠest = () => 6; int šest = pořádŠest(); // žádná návratová hodnota nebo delší metoda // public delegate void ThreadStart(); new System.Threading.Thread(() => { System.Diagnostics.Debug.Print("Nazdar světe!"); }).Start(); // více parametrů // public delegate void EventHandler(object sender, EventArgs e); Microsoft.SPOT.Application.Startup += (sender, e) => { System.Diagnostics.Debug.Print("Aplikace spuštěna."); };

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.

Expression Trees

Účel: Uložení postupu vyhodnocování funkcí, umožňuje optimalizaci dotazů. Podrobnosti

Příklad:

System.Linq.Expressions.Expression<System.Func<int, int>> méněJedna = x => x - 1;

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.

Query Expressions

Účel: Zahrnout dotazy v přirozeném jazyce do kódu. Podrobnosti

Příklad:

System.Collections.IEnumerable krátkáA = from s in new string[] { "ana", "robert", "alexandra", "alvy" } where s[0] == 'a' orderby s.Length descending select s.ToUpper(); // ekvivalentní s několika extenzními metodami a lambda funkcemi: System.Collections.IEnumerable shortA = new string[] { "ana", "robert", "alexandra", "alvy" }).Where(x => x[0] == 'a').OrderByDescending(y => y.Length).Select(z => z.ToUpper());

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.

Anonymous Types

Účel: Zabalit několik vlastností pro čtení bez potřeby deklarovat typ, umožňuje selekci v dotazech. Podrobnosti

Příklad:

object kamarád = new { Jméno = "குமார்", Věk = 12 };

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).

Partial Methods

Úč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

Příklad:

// Window1.μg.cs - generovaný kód public partial class Window1 { partial void OnComponentsInitialized(); public Window1() { InitializeComponents(); OnComponentsInitialized(); } ... } // Window1.cs - vývojářův kód public partial class Window1 { partial void OnComponentsInitialized() { // kód vašeho konstruktoru } }

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í.

Stav: Funguje bez problémů.

Novinky v C# 4.0

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.

Dynamic Lookup

Účel: Obejít statickou kontrolů typů a řešit vše až za běhu. Podrobnosti

Příklad:

dynamic expando = new System.Dynamic.ExpandoObject(); expando.VeseláVlastnost = "Jabadabadů";

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).

Named Parameters

Účel: Odstranit nutnost si pamatovat nebo vyhledávat pořadí parametrů. Podrobnosti

Příklad:

Microsoft.SPOT.Net.NetworkInformation.NetworkInterface.EnableStaticIP(gatewayAddress: "88.86.110.254", ipAddress: "88.86.110.84", subnetMask = "255.255.255.0");

Způsobí: Že kompilátor přeuspořádá parametry do správného pořadí.

Stav: Funguje bez problémů.

Optional Parameters

Účel: Stanovit výchozí hodnoty parametrů, které pak mohou být vynechány. Podrobnosti

Příklad:

public void VypišŘádky(string řádka, int počet = 2) { for (int i = 0; i < počet; i++) System.Diagnostics.Debug.Print(řádka); } ... PrintLines("Nazdar světe!"); // Vypíše 2 řádky PrintLines("Nazdar světe!", 5); // Vypíše 5 řádků

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.

Variance in Generic Types

Účel: Umožnit implicitní konverzi generických typů. Podrobnosti

Příklad:

System.Collections.Generic.IEnumerable<object> objekty = new System.Collections.Generic.List<string>();

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.

Comments
Sign in using Live ID to be able to post comments.