Programujeme v jazyku C# III. Diel 13. – Novinky v C#3 I.

Michal Čižmár  /  16. 04. 2008, 14:46

Tento diel začína sériu článkov o novinkách, ktoré môžeme nájsť v C#3. V prvom dieli si nainštalujeme vývojové prostredie a povieme si niečo o Extenzívnych (rozširujúcich) metódach.

Približne po dvoch mesiacoch sa hlásim s novým článkom, dúfam že padne na úrodnú pôdu a nasledujúca séria článkov Vám zodpovie na Vaše otázky, či sa napr. pustiť do .NET 3.5 alebo nie. Tento článok píšem opäť v blízkosti najdôležitejšej osoby v mojom živote a aj vďake nej práve vzniká ;-)

 

>>Trocha histórie

Určite ste si všimli, že už dlhšiu dobu nám Microsoft ponúkal .NET 3 pre vývoj programov. Bol stále použiteľný vo VisualStudiu 2005. Priniesol nám množinu nových funkcií, rozdelených do viacerých tzv. Foundations.

Keďže kvôli týmto pridaným funkciám nebola potrebná zmena syntaxe, stále sme si vystačili so C#2. Jednotlivé „Foundations“ sa dali doinštalovať samostatne, takže ste sa napr. mohli stretnúť s tým, že program vyžadoval .NET 2 a WWF (Windows Worklow Foundation). Pribudla možnosť rozšírenia ASP.NET komponentov s technológiou AJAX (ako samostatne doinštalovatelné knižnice).

Priznám sa Vám, že aj keď ma veľmi zaujalo napr. WWF alebo WPF (Windows Presentation Foundation), stále som mal pocit, že to nie je ani zďaleka celistvé (akoby bolo ešte potrebné zintegrovať jednotlivé Foundations medzi sebou) a  nepoužíval som ich vo svojich programoch, keďže som si nebol istý, či sa to na koniec ujme a asi som spravil dobre ;-)

S nástupom .NET 3.5 prichádza C#3. Boli zachované všetky Foundations, nie sú tu ale presne tie isté z .NET 3, sú rozšírené a oveľa viac prepojené (najlepším príkladom pre zainteresovaných je lepšie prepojenie WWF a WCF (Windows Comunication Foundation)).

Ďalší pojem, ktorý hlavne rezonuje pri predstavovaní .NET 3.5 je LINQ. Je to nielen rozšírenie funkcionality, ale spôsob práce s dátami, či už databázovými, uložených v XML alebo proste len v poli. Aby to bolo umožnené, bolo potrebné rozšírenie syntaxe jazyka C#.

Samostatné nové fičúrie ;-) v C#3 sa môžu zdať len ako nový syntaktický cukor (ani nie kryštálový, skôr len práškový ;-) ) bez ktorého sa dá zaobísť, ba čo viac, umožňuje také triky, ktoré môžu nesprávnym používaním oveľa viac zneprehľadniť kód.

Ak Vám bude niekto ukazovať ako hlavnú výhodu to, že napr. z 300 riadkového kódu spraví program na 40 riadkov, všímajte si, či je kód naďalej rovnako ľahko čitateľný aj pre ľudí, ktorý neboli zainteresovaní priamo do jeho písania, alebo či bude rovnako ľahko aj do budúcna rozširovateľný či refaktorovateľný.

Skôr si všímajte, alebo sa pýtajte, kde je to správne miesto danú novinku syntaxe použiť a aké riziká to so sebou prináša. Preto sa budem snažiť aj túto sériu článkov písať v podobnom štýle.

>>Aké vývojové prostredie?

Nuž biznis je tvrdý a my chudáci obyčajní programátori musíme nejak presvedčiť šéfstvo, že potrebujeme kúpiť nové VisualStudio 2008(vyvíjané pod kódovým menom „Orcas“), ak chcem používať C#3, pretože nie je možné ho používať v plnej miere vo verzii 2005. Alebo nie???

Odpoveď je, že nie, nepotrebujeme. Skúšal som VisualStudio 2008 Express a zistil som, že na to aby som Vám ukázal všetky novinky v .NET 3.5 a C#3 oproti .NET 2 a C#2, tak tadeto cesta nevedie.

Veď aký ma zmysel ukazovať výhody WWF keď vám nemôžem ukázať, ako si môžete pekne vizuálne nadesignovať procesy. Ako som už povedal, naschvál vynechávam možnosť, ukazovať to na .NET 3.

 

Našťastie máme riešenie a to je SharpDevelop v. 3.
Ak nechcete robiť vizuálne ASP.NET stránky. Tak podľa mňa, je SharpDevelop oveľa lepší nástroj ako platené VisualStudio Standart (hoc aká verzia).
Zadarmo máte po ruke integrované NUnit testy, Code Coverage, určitý typ CVS, FxCop, Diagram tried, možnosť vyvíjať pre ľubovoľnú verziu C# a dokonca aj pre MONO. Dobré nie?

 
Tu si stiahnite .NET 3.5

Tu si môžete stiahnuť SDK, ale ak máte skoro stále prístup na Net, tak radšej šetrite trafik a využívajte len online MSDN.

 

Na tejto stránke som si stiahol posledný build a začal som skúšať. Zistil som, že všetko má svoje chyby (keďže je vo vývoji, dalo sa to čakať) a je potrebný malý tunning ;-). Možno, že vo verzii, ktorú ste si práve stiahli, ale už nie je potrebný.

takže ho treba použiť, iba ak Vám počas kompilácie Vášeho programu napíše približne niečo takéto:

The "Microsoft.Build.Tasks.Delete" task could not be loaded from the assembly C:WINDOWSMicrosoft.NETFrameworkv3.5Microsoft.Build.Tasks.dll. Could not load file or assembly 'file:///C:WINDOWSMicrosoft.NETFrameworkv3.5Microsoft.Build.Tasks.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct, and that the assembly and all its dependencies are available. (MSB4062)

Otvoríte si v textovom editore tento súbor:

C:Program FilesMSBuildMicrosoftWindows Workflow Foundationv3.0Workflow.Targets

 
A úplne deštruktívne zmažte tento riadok

<UsingTask TaskName="Microsoft.Build.Tasks.Delete" AssemblyFile="$(MSBuildBinPath)Microsoft.Build.Tasks.dll" />

 
 
>>Čo je teda nové v C# 3?

Nebudem to tu stručne opisovať, dávam Vám ich zoznam a postupne, v jednotlivých článkoch, sa dozviete detaily.

 

Tram-ta-ta-tá , Vážené dámy a páni, predstavujeme Vám hlavné novinky v C#3 ;-)

  • LINQ
  • Lambda výrazy
  • Extenzné metódy
  • Inicializátory objektov
  • Anonymne typy
  • Implicitné lokálne premenné,
  • Výrazové stromy
  • Automatické vlastnosti
 
A teraz poďme na ne po jednom.
 

>>Extenzné (rozširujúce) metódy

Je to veľmi silný nástroj, ktorý nám poskytuje C#3. Umožňuje rozšíriť funkcionalitu už existujúcich tried (napr. keď nemáte prístup k ich zdrojovým súborom).  Nie je to ale až taká nová vec na poli programovania, môžeme to nájsť aj v iných programovacích jazykoch. SmallTalk to už má okolo 30 rokov a tiež sa to používa v RUBY.
Platia tam určité pravidlá, ktoré si postupne  ukážeme.

 

Hlavnou zásadou je, že sú to metódy, ktoré iba pracujú s daným (rozširovaným) objektom,  teda nijak nezasahujú do jeho vnútorného kódu, využívajú iba vonkajšie rozhranie danej triedy a z  toho vyplýva, že to musia byť iba statické metódy, ale sú použiteľné iba s inštanciami objektov, to je jedna z vlastností, s ktorou sa líšia od štandardných statických metód.  

 

Výhodou je, že môžete takto trochu rozšíriť funkcionalitu tried, ktoré sa nedajú dediť. Napr. triedu String, Int a všeobecne hlavne triedy v rámci .NET-u. Microsoft zaviedol tento nástroj najmä kvôli potrebám začlenenia LINQ.

 

Do budúcna sa plánuje aj z rozširujúcimi vlastnosťami (Properties) a udalosťami (Events), ale zatiaľ to ani v C#3 nie je implementované.

 

Odporúčam množinu takýchto rozširujúcich funkcií umiestniť do samostatného priestoru mien. Potom jeho inkludnutím do projektu sa sprístupní aj daná funkcionalita a nemusí byt teda platná v celom projekte. Viem si predstaviť, že takto vznikne zopár rozširujúcich balíčkov od .NET nadšencov, ktorí sa budú snažiť spraviť prácu s .NET-om ľahšiu.

 

>>Prvý jednoduchý príklad

V príklade sú dve rozširujúce metódy. Jedna rozširuje vlastnú triedu a druha existujúcu triedu Single32 t.j int.
Na obrázku pod príkladom môžete vidieť, ako IntelliSense ponúka už názov našej rozširujúcej metódu medzi ostatnými štandardnými metódami patriace pod Int. 

 
Príklad 3.13.1 

using System;
 
namespace ExstensionMethods
{
 class PrvaTrieda
 {
  int hodnota = 5;

  public int GetHodnota()
  {
   return hodnota;
  }
 }

 // cela trieda musi byt definovana ako static
 static class FunkcneRozsirenia
 {
  //Rozisrenie pre class PrvaTrieda
  //this + nazov triedy, ktoru rozsirujem
  public static int GetHodnotaPlus1(this PrvaTrieda item)
  {
   return item.GetHodnota() + 1;
  }

  //Rozsirenie pre class Single32 = int
  public static int GetHodnotaPlus2(this int i)
  {
   return i + 1;
  }
 }

 class Program
 {
  public static void Main(string[] args)
  {

   PrvaTrieda tr = new PrvaTrieda();
   int result = tr.GetHodnotaPlus1();
   Console.WriteLine(result);

   int a = 5; // rozsirenia funkcnionalita >>int
   result = a.GetHodnotaPlus2();
   Console.WriteLine(result);

   Console.Write("Press any key to continue . . . ");
   Console.ReadKey(true);
  }
 }
}

 Priklad 3 13 1

 

Obr. 3.13.1
 
 

Postup vytvorenia extenznej metódy:

  1. Vytvoriť statickú triedu
  2. V nej vytvoriť statickú metódu, ktorej vstupný argumenty má takýto tvar:
    this   meno_rozsirovanej_triedy    nazov_premennej  plus môžu nasledovať ďalšie klasické parametre
 
 
Ďalšie pravidlá:

-   Zaujímavé je, že môžete vytvoriť rozširujúcu metódu s tou istou hlavičkou ako už daná rozširovaná trieda obsahuje. Kompilátor za to nerepce, až na to, že aj tak sa na koniec použije tá natívna metóda, ktorá už existovala. Žeby chyba kompilátora? :-)

-   Všetci potomkovia rozšírenej triedy prevezmú rozšírenú metódu. Takže ak napríklad rozšírite triedu object, tak ste práve rozšírili všetky triedy v .Net!
        

V diskusiách na internete môžete nájsť veľa protichodných a zmiešaných názorov na túto fičúru ;-). Hlavným argumentom je, že to narúša objektovo orientovaný princíp.

Myslím si, že ak to vo svojich programoch nepreženiete a použijete tento nástroj keď to už ozaj nepôjde ináč, tak nič nepokazíte. Na druhej strane, intenzívne využívane rozširujúcich metód môže mať za následok zneprehľadnenie kódu a ťažšie hľadanie chýb.
Myslím si, že najčastejšie budete používať už existujúce extenzné metódy, ktoré vznikli hlavne kvôli LINQ a nie vyrábať vlastné.  

 
 
>>Druhý jednoduchý príklad

V tomto príklade rozšírime triedu String a ukážeme si, že rozširujúca metóda môže mať aj viac argumentov, ako len ten s kľúčovým slovíčkom this.

 
Príklad 3.13.2

using System;
using System.Collections.Generic;
 
namespace ExtMetody2
{
 public static class MojeExtMetody
 {
  /// <summary>
  /// Otoci poradie znakov v retazci
  /// </summary>
  /// <param name="input"></param>
  /// <param name="length">
  /// kolko znakov od konca ma vratit</param>
  /// <returns></returns>
  public static string Reverse(this string input,int length)
  {
   char [] pole = input.ToCharArray();
   List<char> list = new List<char>();

   foreach(char c in pole)
   list.Add(c);

   list.Reverse();

   char [] pole2 = list.ToArray();
   string result = new String(pole2);
   return result.Substring(0,length);
  }
 }

 class Program
 {
  public static void Main(string[] args)
  {
   string text = "Ahoj ako sa mas?";

   //Pouzite rozsirujucej metody na String
   //Pozor, nie String.Reverse(text);
   Console.WriteLine(text.Reverse(text.Length));

   Console.Write("Press any key to continue . . . ");
   Console.ReadKey(true);
  }
 }
}

 
 

Obr. 3.13.2

 

>>Čo bude nabudúce?

Buď podľa toho, čo uznám za vhodné, alebo podľa ohlasu Vás čitateľov, rozoberieme ďalšie dva nové syntaktické cukríky ;-).

 

[príklady na stiahnutie]

Príklad 3.13.1

Príklad 3.13.2

 

[Iné zdroje]
http://en.wikipedia.org/wiki/Extension_method

Trochu kritický pohlad na rozširujúce metódy.

 

[Predchádzajúce diely]
Programujeme v jazyku C# III. Diel 12. – Šifrovanie IV (+ celý program na stiahnutie)
Programujeme v jazyku C# III. Diel 11. – Šifrovanie III
Programujeme v jazyku C# III. Diel 10. – Šifrovanie II
Programujeme v jazyku C# III. Diel 9. – Regulárne výrazy IV


SEE YOU!

 

Autor: Michal Čižmár
micitn@orangemail.sk

 

Neprehliadnite: