Skip Navigation Links.
Skip Navigation Links.

.net student

microsoft

Vyhledávání v obsahu portálu


Přihlášení uživatele

Přihlášení uživatele

Členové:
  • Poslední nový uživatel Poslední: liborsky
  • Nový dnes Dnes nových 1
  • Nový včera Včera nových: 0
  • Počet uživatelů: Celkem: 4708
Lidé online:
  • Návštěvníci: Návštěvníků: 24
  • Registrovaných Členů: 0
  • Celkem Celkem: 24
Mapa Stranek

Úvod do LINQ

S oficiálním příchodem .NET frameworku 3.5 vyšla na svět finální verze projektu, který se dá označit za revoluci v přístupu k datům na platformě .NET. Nejedná se o nic jiného než o projekt LINQ, který je v článku představen spolu s bližším pohledem na jeho implementaci s názvem LINQ to Objects.

Co je LINQ?

Od svého počátku bylo možné v aplikacích postavených nad platformou .NET pracovat z relačními či hierarchickými daty a to hned několika způsoby. V případě dat, která jsou uložena v relační databázi je možné přistupovat skrze známé rozhraní ADO .NET a to jak v připojeném tak odpojeném režimu. Pokud jsou data reprezentována hierarchicky v populárním formátu XML lze využívat typů z assembly System.Xml a pracovat s těmito daty buď pomocí DOM nebo je zpracovávat sekvenčně. Nyní ovšem přichází technologie, která umožňuje zcela nový způsob práce s daty na platformě .NET a nese název LINQ, což znamená Language INtegrated Query.

LINQ přináší podporu dotazování přímo do .NET programovacího jazyku a to s sebou nese hned několik výhod oproti výše zmíněným postupům.  První a asi nejvíce viditelnou novinkou, které si ihned všimne kdokoli, kdo začne pracovat s daty v jazyku C# 3.0 nebo Visual Basic 9, je nová paleta klíčových slov pro provádění LINQ dotazů nad daty. Další velmi příjemnou novinkou, která plyne z integrace dotazování přímo do .NET programovacího jazyku je odhalení chyb již v době kompilace, takže vaše dotazy budou kontrolovány hned a drtivá většina chyb nemá šanci projevit se až za běhu aplikace.

Pomocí tohoto nového přístupu je možné pracovat takřka s jakýmikoliv daty, protože architektura technologie LINQ je navržena tak, že je možné tvořit její implementace pro jednotlivé datové zdroje. Je to podobné jako v ADO .NET, kde je možné implementací rozhraní, vytvořit .NET provider pro specifický typ databáze, avšak v LINQ tato rozšiřitelnost nezůstává jenom u relačních databází a je mnohem abstraktnější. Této volnosti je dosaženo hlavně díky novince v .NET 3.5, kterou jsou Expression Trees, jež umožňují pracovat s kódem jako z daty a tím pádem může být LINQ dotaz konkrétním providerem přeložen pro adekvátní datový zdroj a je jedno jestli se jedná o data relační, hierarchická či nějaká jiná.  Tento, dle mého názoru skvělý koncept, má mimo jiné za následek, že díky LINQ se sjednocuje způsob práce s daty různých druhů. 

Spolu s .NET frameworkem 3.5 je dodáno několik oficiálních implementací LINQ od Microsoftu, které by měly pokrýt běžné potřeby pro tvorbu aplikací pracujících s daty. Jedná se o tyto implementace :

  • LINQ to Objects – Implementace LINQ pro standardní kolekce nacházející se v paměti
  • LINQ to SQL – Implementace LINQ pro Microsoft SQL Server 2000 a vyšší
  • LINQ to XML – Implementace LINQ pro práci s XML daty
  • LINQ to DataSet – Implementace LINQ pro práci s ADO .NET datasety

I přestože primárním přínosem LINQ je maximální efektivita při dotazování nad daty, u většiny implementací LINQ to u dotazování nekončí a kromě toho je možné data nejen efektivně dotazovat, ale i také modikovat. Takže například v případě LINQ to SQL nám do rukou přichází nástroj, který nejen, že umožní provádět dotazy nad databází SQL server jednoduše a typově ze C# 3.0, VB 9 nebo jiného jazyku, ale díky možnosti data i modifikovat se z této implementace LINQ stává skvěle použitelný objektově-relační mapper.

LINQ to Objects

Základní a nejjednodušeji použitelnou implementací LINQ je jeho implementace LINQ to Objects. Tato implementace je určena, jak bylo zmíněno výše, pro použití se standardními kolekcemi, které se nacházejí pouze a jenom v paměti. Takže je možné velmi jednoduše provádět dotazy nad kolekcemi stylem podobným jazyku SQL bez toho, aby bylo nutné vymýšlet nějaké vlastní algoritmy vyhledávání. Jakým způsobem toho bylo docíleno a jakými cestami lze LINQ to Objects využít je rozebráno na následujících řádcích.

Rozšíření kolekcí v .NET 3.5

Kolekcí, která může být použita v LINQ, je kterákoli kolekce, jež implementuje generické rozhraní IEnumerable<T>. Toto rozhraní se objevilo s příchodem generik v .NET 2.0 a je implementováno kolekcemi ve jmenném prostoru System.Collections.Generics a také obyčejnými poli. To znamená, že vyhledání prvků v kolekci a jejich sestupné seřazení může být provedeno například takto: 

int[] ints = new int[5] { 1, 2, 3, 4, 5 };
//vyhledani prvku vetsich nez 4
IEnumerable<int> result = ints.Where(i => i < 4).OrderByDescending(i => i);

 

foreach (int i in result)
{
     Console.WriteLine(i);
}

Bylo totiž využito jedné z novinek v C# 3.0 (či VB9), kterými jsou extension methods, umožňující rozšíření stávajících typů bez jejich změny. Tímto způsobem byly rozšířeny veškeré typy implementující  již zmíněné rozhraní IEnumerable<T> o bohatou množinu nových metod, které slouží právě k provádění dotazů nad daty. Tato množina metod je označována také jako standard query operators a najdeme zde metody jako například Where pro definici omezení prvků ve výsledkové sadě, metodu Select pro implementaci projekce, či také OrderBy metodu pro seřazení výsledku a samozřejmě mnoho dalších.  LINQ extension metody pro typ IEnumerable<T> jsou implementovány ve třídě Enumerable nacházející se uvnitř jmenného prostoru System.Linq, takže pokud by někdo potřeboval použít LINQ standard query operators v jazyku, který nedisponuje extension metodami, může využít služeb statických metod v této třídě obsažených.

V extension metodách pro typ IEnumerable<T> je velice často nutné použít instanci jednoho z delegátů s názvem Func. Delegáty Func, které byly do .NET frameworku 3.5 přidány, jsou velmi obecné a formou generických argumentů je v jejich případě určován typ vstupních argumentů a typ návratové hodnoty. Díky existenci těchto delegátů není nutné explicitně definovat nový typ delegáta. Instance těchto delegátů jsou nejčastěji tvořeny pomocí lambda výrazů, jež se nově objevily v C# 3.0 a umožňují výrazně zkrátit zápis anonymní metody. Takže díky skutečnosti, že jsou jako parametry extension metod pro LINQ použity instance delegátů, je k dispozici velká volnost například v implementaci restrikce (Where) či projekce (Select) a jsou k dispozici veškeré metody implementované na typech prvků. V případě, že je tedy typ prvku String může být dotaz naimplementován například tímto způsobem: 

List<string> strings = new List<string>() { "Hello", "Ahoj", "Hi" };
IEnumerable<string> result = strings.Where(s => s.StartsWith("H")).Select(s => s.ToUpper());

 

//vypise "HELLO" a "HI"
foreach (string str in result)
{
     Console.WriteLine(str);
}

A samozřejmě může být v dotazu použito i jakýchkoli uživatelsky definovaných typů. V následujícím příkladu je použito projekce takovým způsobem, že je místo celých objektů typu Customer, nad kterými je aplikován dotaz, vrácena kolekce objektů typu String, představující sestavené celé jméno zákazníka. 

IEnumerable<Customer> customers = CustomerDB.GetCustomers();
IEnumerable<string> result = customers
                             .Where(c => c.Surname.Length > 3)
                             .Select(c => c.FirstName + " " + c.Surname);

Použití LINQ nad „starými“ kolekcemi

Extension metody pro LINQ jsou, jak bylo zmíněno výše, implementovány nad typem IEnumerable<T>. To znamená, že LINQ metody je možné použít pouze na generických kolekcích a například metodu Where bychom na objektu typu ArrayList hledali marně. Ovšem i z tohoto problému existuje východisko a to použitím generické extension metody Cast, která je definována nad typem IEnumerable. Tímto dosáhneme tvorby generické kolekce z kolekce obyčejné, která ovšem musí obsahovat pouze prvky definovaného typu, jinak dojde k vyhození výjimky InvalidCastException.

ArrayList list = new ArrayList() { 1, 2, 3, 4, 5 };
//prevod na generickou kolekci a pouziti LINQ
IEnumerable<int> result = list.Cast<int>().Select(i => i).Where(i => i < 4);

Nová klíčová slova v C# 3.0

Nyní už víme, jakým způsobem byl LINQ zanesen do standardních kolekcí .NET frameworku a také jak jej použít pomocí extension metod. I přestože je, dle mého názoru, použití extension metod poměrně přehledné, lze LINQ z jazyku C# 3.0 (či VB9) použít ještě jednodušeji a to použitím takzvaných query keywords, což není nic jiného než skupina nových klíčových slov pro realizaci LINQ dotazů. Díky existenci query keywords lze napsat LINQ dotaz nad kolekcí třeba tímto způsobem:

int[] numbers = new int[5] { 1, 2, 3, 4, 5 };
//vyhledani prvku vetsich nez 4
IEnumerable<int> result = from num in numbers
                          where num < 4
                          orderby num descending
                          select num;

Tato klíčová slova jsou, stejně jako všechny novinky v C# 3.0, syntaktickým cukrem, který ulehčuje práci a také zpřehledňuje kód, který v tomto případě již opravdu silně připomíná SQL akorát s tím rozdílem, že projekce pomocí klíčového slova select je až na konci dotazu a naopak klauzule from je hned na začátku (a díky tomu nám intellisense ve VS 2008 může skvěle napovídat, protože je hned známo, jakého typu je datový zdroj). Nicméně pokud se podíváme do zkompilovaného IL kódu, zjistíme, že se tento dotaz zkompiloval do použití výše zmíněných extension metod (které se dále kompilují na standardní volání statických metod na třídě Enumerable). Nová klíčová slova nezastupují veškerou funkčnost, která je dostupná pomocí standard query operators, ale pouze jejich určitou část, která je nejpoužívanější, jako restrikce, projekce, seskupování, řazení či propojení.

Pojďme se na query keywords podívat blíže. V následujícím seznamu je uveden seznam těchto nových klíčových slov včetně popisu funkčnosti a případného ekvivalentu v extension metodách typu IEnumerable<T>.

Klíčové slovo  Metoda na IEnumerable<T> Popis
from žádná První klíčové slovo v dotazu. Slouží ke specifikaci datového zdroje, nad kterým je prováděn dotaz.
where Where Slouží k definici podmínky restrikce pro výsledek. Pokud podmínka vrátí true, prvek je zahrnut do výsledku.
select Select Používá se k implementaci projekce, kde jsou pouze některé datové složky objektu použity ve výsledku. Uvádí se vždy na konci dotazu.
group GroupBy Slouží k seskupování prvků ve výsledku podle určitého klíče. K použití toho slova se váže použití nového klíčového slova by. Může jím být zakončen dotaz.
into žádná Používá se v kombinaci se slovem group, join nebo select k uložení jeho výsledku a další možné práci s tímto výsledkem.
orderby OrderBy, OrderByDescending  Slouží k řazení prvků ve výsledku podle definovaných kritérií. Pro sestupné řazení je možné použít s novým klíčovým slovem descending.
join Join, GroupJoin Používá se k propojení prvků z různých datových zdrojů na základě definované podmínky ekvivalence. V kombinaci s tímto slovem se používají nová klíčová slova equals a on.
let žádná Slouží k definici lokální proměnné v rámci dotazu, do které může být přiřazena jak sekvence elementů, tak jednoduchá hodnota.

Obecná forma jednoduchého LINQ dotazu pomocí query keywords v C# 3.0 tedy vypadá nějak takto:

from [typ] proměnná in datový_zdroj
[where] podmínka_restrikce
[orderby] klíč_řazení [descending]
select výraz_projekce

Jak je vidět, tak datový typ prvku nemusí být ve from klauzuli dotazu explicitně určen a je, stejně jako v případě klíčového slova var, odvozen v době kompilace. Ovšem ne vždy může být datový typ prvku v sekvenci takto odvozen. V případě generické kolekce to možné je, ovšem v případě negenerické kolekce jako je například ArrayList, musí být kolekce buď pomocí Cast metody převedena na kolekci generickou, nebo v případě C# 3.0 query keywords stačí v klauzuli from typ prvku explicitně uvést. Ovšem v případě nesprávně definice typu prvku hrozí opět výjimka InvalidCastException

ArrayList numbers = new ArrayList() { 1, 2, 3, 4, 5 };
var result = from int n in numbers
             where n < 4
             orderby n descending
             select n;

Použití základních klíčových slov from, select a orderby bylo již demonstrováno v předchozích příkladech, ovšem na použití nových klíčových slov group, join a let se podíváme v příkladech následujících.

Seskupování pomocí klíčového slova group

Pomocí nového klíčového slova group je možné dosáhnout seskupení výsledku podle určitého klíče podobně jako v jazyku SQL. Jelikož je klíč pro seskupení získán výrazem, je možné použit jako klíč vlastnost objektu, složení několika vlastností (složený klíč) nebo cokoliv jiného co lze vyjádřit výrazem jako například seskupení podle prvního písmena v příjmení zákazníka, jak ukazuje následující příklad.

IEnumerable<Customer> customers = CustomerDB.GetCustomers();
var result = from cust in customers
             group cust by cust.Surname[0];

Jelikož jsou při použití klíčového slova group vrácena do výsledku seskupení, jež jsou reprezentována objekty typu IGrouping, je návratový typ dotazu v příkladu kolekce IEnumerable<IGrouping<char, Customer>>. Naštěstí je možné využít nového klíčového slova var a tedy neuvádět explicitně proměnnou tohoto typu. Při procházení výsledku dotazu je potřeba použít vnořených cyklů, kde první slouží k iteraci jednotlivými seskupeními a druhý cyklus již iteruje prvky v seskupení. 

//prochazeni jednotlivych seskupeni
foreach (IGrouping<char, Customer> group in result)
{
            Console.WriteLine(group.Key);
            Console.WriteLine("-------------");
            //prochazeni jendotlivych zaznamu v seskupeni
            foreach (Customer cust in group)
            {
                Console.WriteLine(cust.Surname + " " + cust.FirstName);
            }
            Console.WriteLine();
}

V případě, že bychom chtěli se vzniklými seskupeními ještě dále v rámci dotazu pracovat, bylo by nutné využít klíčového slova into, pomocí kterého definujeme lokální proměnnou v rámci dotazu a pomocí této proměnné je možné se seskupeními ještě dále pracovat. 

var result = from cust in customers
             group cust by cust.Surname[0] into g
             orderby g.Key descending
             select g;

Propojení pomocí klíčového slova join

Propojení mezi objekty (join), které mezi sebou nemají přímou asociaci, je možné implementovat za pomocí nového klíčového slova join. Podobně jako v jazyku SQL je i v LINQ možné použít inner join nebo outer join. Pokud bychom chtěli vytvořit seznam dvojic produkt a kategorie, do které produkt patří, realizovali bychom to v LINQ třeba takovýmto inner joinem: 

IEnumerable<Product> products = ProductsDB.GetProducts();
IEnumerable<Category> categories = CategoryDB.GetCategories();

var result = from c in categories
             join p in products on c.ID equals p.CategoryID
             select new {ProductName = p.Name, CategoryName = c.Name };
           
foreach (var pair in result)
{
    Console.WriteLine(pair.ProductName + " - " + pair.CategoryName);

S použitím propojení pomocí klíčového slova join je potřeba použít i dalších klíčových slov on a equals, které slouží k definici podmínky propojení. Dobré je vědět, že použití klíčového slova equals nelze nahradit použitím operátoru == a také závisí na pořadí použitých zdrojových sekvencích, kde na levou stranu vždy patří sekvence, ke které hledáme podřízené záznamy (categories) a na stranu pravou sekvence s podřízenými záznamy (products). V případě prohození stran dojde ke kompilační chybě. V příkladu je výsledná dvojice produkt-kategorie reprezentována anonymním typem, který je deklarován v rámci dotazu, a proto je nezbytné použití klíčového slova var na proměnnou výsledku. Jelikož se v tomto standardním případě LINQ dotazu s propojením použit inner join, tak v případě, že by byla definována kategorie, ke které neexistují produkty, nebyla by do výsledku zahrnuta.

Pokud bychom potřebovali spolu s propojením zároveň seskupovat podř&;iacute;zené prvky, je možné použít takzvaný group join, kterého dosáhneme použitím klíčového slova into. Takže bude možné po propojení vytvořit dvojici, kde ke každé kategorii je seznam podřízených produktů.

var result = from c in categories
             join p in products on c.ID equals p.CategoryID into prodsForCategory
             select new { CategoryName = c.Name, Products = prodsForCategory };
           
foreach (var item in result)
{
        Console.WriteLine(item.CategoryName);
        Console.WriteLine("---------------------------");
        foreach (Product p in item.Products)
        {
            Console.WriteLine(p.Name);
        }
        Console.WriteLine();
}

Možné je implementovat také takzvaný left outer join, při jehož použití jsou do výsledku zahrnuty i položky, pro které neexistují podřízené záznamy (na rozdíl od inner join). Za tímto účelem je možné použit druhou from klauzuli v kombinaci s metodou DefaultIfEmpty, pomocí které lze vytvořit výchozí podřízený záznam pro případ, že nebyl žádný jiný nalezen. 

var result = from c in categories
             join p in products on c.ID equals p.CategoryID into prodsForCategory
             from item in
             prodsForCategory.DefaultIfEmpty(
                              new Product() { Name = "Zadny produkt", CategoryID = 0 })
             select new { CategoryName = c.Name, ProductName = item.Name };

Proměnné pomocí klíčového slova let

V případě komplikovanějších dotazů může přijít vhod nové klíčové slovo let. Díky tomuto klíčovému slovu lze v  LINQ dotazu definovat proměnnou s oborem platnosti pouze v rámci daného dotazu (range variable) a do ní uložit kupříkladu výsledek nějakého pomocného transformačního dotazu nebo obyčejnou pomocnou hodnotu. V následujícím příkladu je klíčového slova let použito k uchování výsledku pomocného dotazu, který převede každý řetězec v kolekci na pole znaků. Současně příklad ukazuje možné použití více než jedné from klauzule v jednom dotazu. 

List<string> strings = new List<string>() { "Hello", "Ahoj" };
var result = from s in strings
             let chars = s.ToCharArray()
             from ch in chars
             where Char.IsUpper(ch)
             select ch;

 

//vypise "H" a "A"
foreach (char ch in result)
{
      Console.WriteLine(ch);
}

Deferred execution

Jednou z vlastností LINQ je, že poměrně velká část z množiny standard query operators metod nejsou spuštěny ihned v době vytvoření LINQ dotazu, jak by možná mnozí očekávali. Takže pokud je v kódu nějaký například takovýto dotaz:

int[] numbers = new int[5] { 1, 2, 3, 4, 5};
IEnumerable<int> result = from n in numbers
                          where n < 4
                          select n;

..není tomu tak, že je do proměnné result ihned dosazen vyhodnocený výsledek dotazu, ale k vyhodnocení dotazu dojde až když je potřeba, což je určitá forma optimalizace, která je protkána celým LINQ a rozhodně ji oceníte například v implementaci LINQ to SQL, kde není proveden dotaz do databáze, dokud není potřeba. Vyhodnocení dotazu je spuštěno až v době, kdy je o to požádáno zavoláním metody GetEnumerator, neboli použitím cyklu foreach. Díky tomu se případné chyby v dotazu nebo datech, které nemohou být odhaleny kompilátorem, projeví až při prvním spuštění dotazu. 

//jeden z prvku je hodnoty null
string[] strings = { "Hello", "Ahoj", null };
//nyni neni dotaz vyhodnocen a radek projde v poradku
IEnumerable<string> result = from s in strings
                             where s.Contains("o")
                             select s;

 

//az ted bude vyhozena vyjimka NullReferenceException
foreach (string s in result)
{
      Console.WriteLine(s);
}

Tato vlastnost, díky které je dotaz vyhodnocován, až v době použití iterátoru se projeví také v případě, že je mezi dvěma spuštěními téhož dotazu provedena změna do datového zdroje. V takovém případě je tato změna dat logicky promítnuta do výsledku druhého provedení dotazu.

int[] numbers = new int[5] { 1, 2, 3, 4, 5};
IEnumerable<int> result = from n in numbers
                          where n < 4
                          select n;
//budou vypsana cisla 1,2,3
foreach (int number in result)
{
    Console.WriteLine(number);
}
//zmena prvku v poli
numbers[0] = 0;
Console.WriteLine("--------------------------");
//budou vypsana cisla 0,2,3
foreach (int number in result)
{
   Console.WriteLine(number);
}

Pokud bychom chtěli tomuto chování zabránit a tedy zajistit, že výsledek již bude neměnný, stačí využít například extension metody ToList, která zajistí spuštění dotazu a transformaci výsledku na obyčejnou kolekci typu IList<T>.

int[] numbers = new int[5] { 1, 2, 3, 4, 5 };
IEnumerable<int> result = (from n in numbers
                           where n < 4
                           select n).ToList();
//budou vypsana cisla 1,2,3
foreach (int number in result)
{
        Console.WriteLine(number);
}
//zmena prvku v poli
numbers[0] = 0;
Console.WriteLine("--------------------------");
//budou vypsana cisla 1,2,3
foreach (int number in result)
{
     Console.WriteLine(number);
}

Stejného chování lze dosáhnout také extension metodami implementujícími agregační funkce jako jsou kupříkladu metody Count, Average, Min nebo Max.

int[] numbers = new int[5] { 1, 2, 3, 4, 5 };
//dotaz je ihned vyhodnocen a vracen pocet elementu
int itemCount = (from n in numbers
                 where n < 4
                 select n).Count();

Závěr 

Toť vše k představení technologie LINQ, kterou se nebojím označit za revoluci  v přístupu k datům z .NET a kterou pravděpodobně čeká velká budoucnost (alespoň u menších až středně velkých aplikací, kde není problém kód dotazu přímo v kódu). Myslím si tak z důvodu, že díky LINQ je zachován stejný koncept dotazování dat nad různými datovými zdroji a díky jeho výborné rozšiřitelnosti bude paleta podporovaných datových zdrojů neustále větší. Příkladem mohou být již existující další implementace jako například LINQ to Hibernate, DbLINQ či LINQ to Amazon. Dalším důvodem je samozřejmě ona integrace do .NET jazyku vedoucí ke kontrole správnosti dotazu již při kompilaci či parádnímu intellisence ve Visual Studio 2008, které efektivitu tvorby dotazů nad daty také zvyšuje. Příště se detailněji podíváme na implementaci LINQ to SQL.

Petr Puš :: 12. února 2008 :: 1466 shlédnutí :: 0 komentářů
kategorie: Databáze a práce s XML, Obecná .Net témata

Comments

Nyní zde nejsou žádné kometáře. Buďte první!
Musíte být přihlášen pro posílání komentářů. Přihlásit se můžete zde
Přehled posledních diskuzí

Přehled posledních diskuzí

  1. ASP.NET programátor zlín [12.16.2008 10:17 odp.]
    Dobrý den,v současné době hledáme programátora na pozici: ASP.NET / C# programátor - Zlín Požadavky: schopnost sam...
  2. RE: MS Fest video [12.08.2008 6:20 odp.]
    AhojVideo záznam bude, po večerech pilně pracujeme na jeho stříhání. Po dokončení se zde určitě vyskytne link na stažení...
  3. MS Fest video [12.04.2008 4:18 odp.]
    Existuje videozáznam z MS Festu konaneho (koncem listopadu 2008) o vikendu na Male Strane na fakulty MFF? Je nekde mozne...
  4. Práce pro programátora [11.25.2008 10:12 dop.]
    Hledám nadšeného programátora na vytvoření webstránek online tv/stream video. V případě zájmu pište na email: projekt@tr...
Novinky z klubů

Novinky z klubů

  1. Programátorské večery: F# 15. prosince 2008
    Ve čtvrtek 18.12.2008 se v rámci programátorských večerů uskuteční přednáška n...
  2. Programátorské večery: VSTO 10. prosince 2008
    Nad kancelářským balíkem MS Office se dají tvořit rozsáhlé aplikace. Od jednod...
  3. Programátorské večery: .NET 4.0 3. prosince 2008
    Zajímá Vás, na co se můžete těšit v nové verzi .NETu? Pak se přijďte podívat n...
  4. Záznamy z programátorských večerů 3. prosince 2008
    Záznamy z prog. večerů (prezentace+dema, občas i nějaké to video) můžete dočasně najít na http://ci...
Co se píše jinde

Co se píše jinde

Windows 7 Beta k dispozici pro MSDN předplatitele

Windows 7 Beta k dispozici pro MSDN předplatitele

Silverlight 2 úvod

Zajímá vás psaní webových aplikací na straně klienta ve vašem oblíbeném nástroji v .NETu? Slyšeli jste o Silverlightu...

PF 2009

Co tak popřát čtenářům programátorského blogu do nového roku? Snad abyste dostávali rozumná zadání a nemuseli tenkou ...

TypeConvertery

V tomto díle si vysvětlíme, co jsou TypeConvertery a k čemu se používají. To si také ukážeme na příkladu.

Atributy jmenného prostoru System.ComponentModel

V tomto článku si ukážeme jak efektivně využívat atributy z jmenného prostoru System.ComponentModel při vytváření vla...