Martin Dybal

Vývojářský blog Martina Dybala

Podle kategorie

LINQ – Rozšíření jazyka C#

2. díl - LINQ – Rozšíření jazyka C#

Martin Dybal       07.05.2016       LINQ       18760 zobrazení

Minule jsme si představili technologii LINQ, v tomhle díle si ukážeme, jak se změnil jazyk C#, aby nám usnadnili dotazování s LINQem. Žádná z nově přidaných možností jazyka není pro použití LINQ nezbytně nutná, jedná se hlavně o syntaktický cukr pro usnadnění dotazování.

Anonymní metody

Anonymní metody byly přidány už do C# 2.0. Anonymní metody nám dovolují definovat funkce přímo tam, kde je potřebujeme. Pro snazší pochopení pomůže ukázka.

Kód bez anonymních metod:

static void Main(string[] args)
{
	var query = Orders.Where(Predicate);
}
private static bool Predicate(Order o)
{
	return o.Price > 1000;
}

Pro usnadnění přibyly anonymní metody.

var query = Orders.Where(delegate(Order o) { return o.Price > 1000; });

Kompilátor si signaturu funkce vygeneruje sám.

Lambda výrazy

Lambda výrazy zkracují zápis Anonymní metody. Zápis pomocí lambda výrazu vypadá takto:

var query = Orders.Where(o => o.Price > 1000); //Lambda výraz s jedním parametrem
var query = Orders.Where((o, i) => o.Price > i); //Lambda  výraz se dvěma parametry

Extension methods

Extension methods nám dovolují přidat metodu k existujcímu datovému typu a tím ho rozšířit. Na pozadí fungují tak, že instanci typu, který mají rozšířit, přejímají jako první parametr. Extension methods nemůžou přistupovat k private a protected prvkům daného typu. Musí být ve statických třídách a musí být statické, datový typ, který rozšiřují, je uveden jako první parametr s klíčovým slovem this.

static void Main(string[] args)
{
	Random rand = new Random();
	int phoneNumber = rand.NextTelephoneNumber();
}

public static class RandomExtensions { public static int NextTelephoneNumber(this Random random) { List<int> prefixs = new List<int> { 736, 775, 604, 605, 608, 730 }; int prefix = prefixs[random.Next(0, prefixs.Count)]; return prefix * 1000000 + random.Next(100000, 1000000); } }

Právě na Extension methods si LINQ hodně zakládá, hodně to zpřehledňuje kód. Právě díky nim máme pocit, že metody LINQu jsou přímo metodami instance.

IList<Order> orders = new List<Order>();
var countOfOrdersWithPriceOverThousand = orders.Count(o => o.Price > 1000);

Anonymní datové typy

Možná jste si toho všimli už v prvním díle. Enumerátor jakého datového typu je v query?

var query = from o in Orders join c in Customers on o.CustomerID equals c.ID
			where o.Price > 1000
			select new {c.Name, c.Address, o.Price};

Jedná se anonymní datový typ, nejedná se o dynamický typ, jako je dynamic, pouze nikde neuvádíme jeho definici, opět ji za nás dodělá kompilátor. Zvláštní je jaké dává kompilátor jména, při pohledu Reflektorem můžeme vidět jména typů jako '<>f__AnonymousType1`3'<int, int, decimal>. Kompilátor generuje anonymní typy jako generické a pak jejich typy parametrizuje, aby předcházel vytváření zbytečného množství datových typů.

Properities anonymního datového typu můžeme i pojmenovávat:

var query = from o in Orders join c in Customers on o.CustomerID equals c.ID
			where o.Price > 1000
			select new {CustomerID = c.ID, OrderID = o.ID, c.Name, c.Address, o.Price};

foreach (var item in query)
{
    Console.WriteLine("{0} {1} {2} {3} {4}",
                        item.CustomerID,
                        item.OrderID,
                        item.Name,
                        item.Address,
                        item.Price);
}

Implicitně typovaná lokální proměnná

Anonymní datové typy by byly k ničemu, kdybychom je neměli jak použít. Proto se C# 3.0 přišlo také klíčové slovo var. Pokud použijeme var, tak za nás kompilátor sám doplní datový typ, pokud ho dokáže jednoznačně určit z výrazu. Datový typ se určuje pouze jednou, pak ho nelze změnit. Následující kód je neplatný!

var count = 5; //datový typ se implicitně určí jako int
count = "pět stránek"; //tohle nelze, count je typu int

Správné použití var:

foreach (var item in query)
{
	Console.WriteLine("Name: {0}\tAdrress: {1}\t\tPrice: {2}", item.Name, item.Address, item.Price);
}

V tomhle případě datový typ položky item neznáme, proto necháme kompilátor, aby ho za nás doplnil. Intellisense pro anonymní datové typy, i implicitně definované typy, funguje. Silná typovost je zachována.

Dotazovací výrazy

Dotazovací výrazy nám umožňují zapisovat LINQ dotazy, tak aby se co podobali SQL syntaxi. Existuje sada klíčových slov from, in, where, let, join, on, equals, into, orderBy, descending, ascending, select, group by. Jedná se o pouhý syntaktický cukr, kompilátor přeloží klauzule na posloupnost volání LINQ metod.

var query = from c in customerList
            where c.City == "London"
            select c; 
//se přeloží jako            
var query = customerList.Where(c => c.City == "London");
var custSuppliers =
    from cust in customerList
    join sup in supplierList on cust.Country equals sup.Country into ss
    from s in ss.DefaultIfEmpty()
    select new
    {
        CompanyName = cust.CompanyName,
        SupplierName = s == null ? string.Empty : s.SupplierName,
        Country = s == null ? string.Empty : s.City,
    };
//se přeloží jako
var custSuppliers = customerList.GroupJoin(supplierList, cust => cust.Country, sup => sup.Country, (cust, ss) => new {cust, ss})
                    .SelectMany(t => t.ss.DefaultIfEmpty(), (t, s) => new
                    {
                        CompanyName = t.cust.CompanyName,
                        SupplierName = s == null ? string.Empty : s.SupplierName,
                        Country = s == null ? string.Empty : s.City,
                    });

Dalším významným rozšířením je yield return, ten bude popsán v příštím díle.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

Opět pár přípomínek

1) Sekce o lamda výrazech je pěkně ošizená, takto čtenář dostává pocit, že lambda = zkrácení zápisu anonynomní metody, nic víc, nic míň. Bude nějaký rozšiřující článek?

2) Není to ani "Extensions method", ani "Extensions methods", ale extension methods.

3) "dovolují přidat metodu k existujcímu datovému typu a tím ho rozšířit" - to je velká lež! Extension metody nikam nic nepřidávají, pouze rozšiřují schopnosti datového typu a to, že mohou být zavolány na instanci daného typu je práce kompilátoru. Pokračuji v dalším bodě.

4) "Na pozadí fungují tak" - to vůbec není pozadí, ale informace, kterou každý, kdo chce takovou metodu napsat musí vědět. O tom, jak extension metody fungují na pozadí nemáš v článku ani řádek. Bude něco v příštích dílech? Něco málo o overload resolution, method invocation extension metod atd. by se hodilo. Jak je to podané zde, vypadá to jako kouzlo, než jako logika kompilátoru. Vše potřebné najdeš v specifikaci, sekce 7.6.4 a 7.6.5.

5) "Implicitní datový typ" - žádné takové rozlišení v .NET neexistuje. To, co máš na mysli se správně nazývá "implicitně typovaná lokální proměnná". Tohle je také blbost "implicitně definované typy". Datové typy v .NET musejí být definované jednoznačně, nicméně "implicitně definované typy lokálních proměnných", to už je jiná.

6) "Dalším významným rozšířením je yield return" - už jsem to psal Filipovi, yiled return není žádné rozšíření. Jsou to pouhá dvě klíčová slova, která ve spojení dávají smysl v kontextu iterátorů, což je také oficiální název, který se pro to používá.

nahlásit spamnahlásit spam -1 / 3 odpovědětodpovědět

Nepřesnosti v názvech jsem opravil. Co se týče zbytku, o každém z odstavců článku se dá napsat podrobný článek, ale to by přesahovalo úroveň tohoto seriálu. Úmyslně jsem se to snažil zjednodušit tak, aby programátor, který začíná nebo přechází na C#, dostal výčet vlastností jazyka, které bude potřebovat k práci s LINQem a ne ho zavalit informacemi, které nutně nepotřebuje.

nahlásit spamnahlásit spam 0 / 2 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback