C Sharp

Z Multimediaexpo.cz

Název tohoto článku není z technických důvodů zcela správný. Správný název by měl být C#.

C# (vyslovované anglicky jako C Sharp, /siː ʃɑɹp/, doslova to označuje notu cis) je vysokoúrovňový objektově orientovaný programovací jazyk vyvinutý firmou Microsoft zároveň s platformou .NET Framework, později schválený standardizačními komisemi ECMA (ECMA-334) a ISO (ISO/IEC 23270). Microsoft založil C# na jazycích C++ a Java (a je tedy nepřímým potomkem jazyka C, ze kterého čerpá syntaxi).

C# lze využít k tvorbě databázových programů, webových aplikací a stránek, webových služeb, formulářových aplikací ve Windows, softwaru pro mobilní zařízení (PDA a mobilní telefony) atd.

Obsah

Cíle jazyka

Standard ECMA[1] definuje současný design C# takto:

  • C# je jednoduchý, moderní, mnohoúčelový a objektově orientovaný programovací jazyk.
  • Jazyk a jeho implementace poskytuje podporu pro principy softwarového inženýrství jako jsou: hlídání hranic polí, detekce použití neinicializovaných proměnných a automatický garbage collector. Důležité jsou také jeho vlastnosti jako: robustnost, trvanlivost a programátorská produktivita.
  • Jazyk je vhodný pro vývoj softwarových komponent distribuovaných v různých prostředích.
  • Přenositelnost zdrojového kódu je velmi důležitá, obzvláště pro ty programátory kteří jsou obeznámeni s C a C++.
  • Mezinárodní podpora je též velmi důležitá.
  • C# je navržen pro psaní aplikací jak pro zařízení se sofistikovanými operačními systémy, tak pro zařízení s omezenými možnostmi.
  • Přestože by programy psané v C# neměly plýtvat s přiděleným procesorovým časem a pamětí, nemohou se měřit s aplikacemi psanými v C nebo jazyce symbolických adres.

Vlastnosti jazyka

Následující popis je založen na specifikaci jazyka C# a dalších dokumentech, které naleznete v sekci Externí odkazy.

  • V C# neexistuje vícenásobná dědičnost - to znamená, že každá třída může být potomkem pouze jedné třídy. Toto rozhodnutí bylo přijato, aby se předešlo komplikacím a přílišné složitosti, která je spojena s vícenásobnou dědičností. Třída může implementovat libovolný počet rozhraní.
  • Neexistují žádné globální proměnné a metody. Všechny funkce a metody musí být deklarovány uvnitř tříd. Náhradou za ně jsou statické metody a proměnné veřejných tříd.
  • V Objektově orientovaném programování se z důvodu dodržení principu zapouzdření často používá vzor, kdy k datovým atributům třídy lze zvenčí přistupovat pouze nepřímo a to pomocí dvou metod get (accessor) a set (mutator). V C# lze místo toho definovat tzv. Property, která zvenčí stále funguje jako datový atribut, ale uvnitř Property si můžeme definovat get a set metody. Výhodou je jednodušší práce s datovým atributem při zachování principu zapouzdření.
  • C# je typově bezpečnější než C++. Jediné výchozí implicitní konverze jsou takové, které jsou považovány za bezpečné jako rozšiřování Integerů (např. z 32 bitového na 64 bitový) nebo konverze z odvozeného typu na typ rodičovský. Neexistuje implicitní konverze z typu Integer na Boolean, ani mezi výčtovým typem enum a typem Integer.
  • C# neobsahuje a ani nepotřebuje dopřednou deklaraci - není důležité pořadí deklarace metod.
  • Jazyk C# je case sensitive - to znamená, že rozlišuje mezi velkými a malými písmeny . Identifikátory "hodnota" a "Hodnota" tedy nejsou na rozdíl od VB.NET ekvivalentní.

CTS

Common Type System je unifikovaný typový systém, používaný všemi jazyky pod .NET Framework, tedy i jazykem C# (dále například VB.NET). Všechny typy, včetně primitivních datových typů jako je Integer, jsou potomky třídy System.Object a dědí od ní i všchny její metody jako například ToString().

Typy v CTS se dělí do dvou základních skupin a to:

  • Hodnotové
  • Referenční

Hodnotové datové typy

Všechny hodnotové datové typy jsou narozdíl od odkazových typů alokované na zásobníku a to z výkonnostních důvodů. Hodnotové datové typy můžeme rozdělit do tří částí

  • Primitivní datové typy - Sem patří celočíselné primitivní datové typy (Byte, Integer, Char,...) a reálné primitivní datové typy reprezentující reálná čísla (float,double,decimal)
  • Struktury - Jedná se o uživatelsky definované datové typy. Na první pohled připomínají třídy, ale nemohou dědit ani být děděny a jako všechny hodnotové typy jsou alokovány na zásobníku a ne na haldě.
  • Výčtové typy - Pojetí výčtů je například oproti Javě značně zjednodušené. V C# je výčet pouze množina předem definovaných hodnot (např. Výčet DnyVTydnu s hodnotami pondělí, úterý,...) bez možnosti definovat si uvnitř výčtu metody nebo atributy, indexery nebo implementovat rozhraní.

Referenční datové typy

Referenční typy neuchovávají na rozdíl od typů hodnotových pouze hodnotu samotnou, ale odkaz na místo v paměti, kde je požadovaná instance uložena. Všechny odkazové typy jsou alokovány na haldě.

Používané platformy

Jazyk C# je navržen tak, aby co nejvíce zohledňoval strukturu Common Language Infrastructure (CLI), se kterou je používán. Většina základních typů v C# přímo odpovídá základním typům v platformě CLI. Návrh jazyka ale nevyžaduje, aby překladač generoval Common Intermediate Language (CIL) nebo jiný konkrétní formát. Teoreticky je možné, aby překladač vytvářel strojový kód podobný běžným překladačům jazyka C++ a jiných, ale v praxi všechny překladače jazyka C# generují CLI.

Historie a verze jazyka

C# 1.0

První verze vydaná v roce 2002 společně s .NET Frameworkem 1.0 obsahovala základní podporu objektového programování, ve které vycházela z jazyka C++ a zkušeností s jejich aktualizací v jazyce Java.

C# 2.0

Na další verzi se čekalo až do konce roku 2005. Mezi její nové vlastnosti patří:

  • Nativní podpora generik vycházející z podpory na úrovni CLI.
  • Částečné a statické třídy.
  • Iterátory.
  • Anonymní metody pro pohodlnější užívání delegátů (odkazů na metody).
  • Nullovatelné hodnotové typy a operátor koalescence.

Generika

Generika, neboli parametrizované typy, neboli parametrický polymorfizmus jsou podporované od C# 2.0. Na rozdíl od C++ šablon jsou .NET parametrizované typy instanciovány za běhu a ne při kompilaci. Proto mohou být použity i v jiném jazyce než byly napsány. Podporují některé funkce nejsou podporovány přímo v C++ šablonách, jako například typové omezení na generických parametrech v rozhraní. Na druhou stranu, C# nepodporuje netypové generické parametry. Na rozdíl od generik v jazyce Java, .NET generika používá zhmotnění parametrizovaných objektů první třídy v CLI Virtual Machine, které umožňuje optimalizace a zachování druhu informací.

Částečné třídy

Částečné třídy umožňují vytvoření třídy, která má být rozdělena mezi několik souborů, přičemž každý soubor obsahuje jeden nebo více členů třídy. Toto se používá hlavně v případě, že některé části třídy jsou generovány automaticky, zatímco jiné jsou psané programátorem. Například tuto funkci používá Visual Studio pro generování kódu při vytváření uživatelského rozhraní v návrháři.

file1.cs:

public partial class MyClass
{
    public void MyMethod1()
    {
        // Kód psaný programátorem
    }
}

file2.cs:

public partial class MyClass
{
    public void MyMethod2()
    {
        // Automaticky generovaný kód
    }
}

Statické třídy

Statické třídy jsou třídy, které nemohou být instanciovány, nemůže se z nich dědit a mohou mít pouze statické členy. Jejich účel je obdobný jako moduly v mnoha procedurálních jazycích.

Nová forma iterátoru poskytující funkčnost generátoru

Nová forma iterátoru poskytující funkčnost generátoru používá konstrukci yield return, podobnou konstrukci yield v jazyce Python.

// Metoda, která vezme iterovatelný vstup (například pole)
// a vrátí všechna sudá čísla.
public static IEnumerable<int> GetEven(IEnumerable<int> numbers)
{
    foreach (int i in numbers)
    {
        if (i % 2 == 0) yield return i;
    }
}

Anonymní delegáty

Jako předchůdce lambda funkcí představených v C# 3.0 jsou do C# 2.0 přidány anonymní delegáti. Zavádějí funkčnost uzavření do C#.[2] Kód uvnitř těla anonymního delegátu má plný přístup k lokálním proměnným, parametrům metody a instancím tříd, kromě out a ref parametrů. Například:

int SumOfArrayElements(int[] array)
{
    int sum = 0;
    Array.ForEach(
        array,
        delegate(int x)
        {
            sum += x;
        }
    );
    return sum;
}

Možnost nastavení jiné přístupnosti pro čtení a zapisování vlastností třídy

Například:

string status = string.Empty;
 
public string Status
{
    get { return status; }             // kdokoliv může číst vlastnost,
    protected set { status = value; }  // ale pouze potomci ji mohou zapisovat
}

Nullovatelné typy

Nullovatelné typy (označené otazníkem, např. int? i = null) přidávají hodnotu null do množiny povolených hodnot pro jakýkoliv datový typ. To poskytuje lepší interakci s SQL databázemi, které mohou používat hodnotou null odpovídající primitivním typům v C#. Například v SQL INTEGER NULL odpovídá v C# int?.

Operátor koalescence

Operátor ?? je nazýván operátorem koalescence a je používán pro definování implicitní hodnoty nullovatelných typů a stejně tak i referenčních typů. Operátor vrací levý operand, pokud není jeho hodnota rovna null. V opačném případě vrací pravý operátor.[3]

object nullObj = null; 
object obj = new Object(); 
return nullObj ?? obj; // vrací obj

Primárně se tento operátor používá k přiřazení hodnoty nullovatelného typu do nenullovatelné proměnné:

int? i = null;
int j = i ?? 0; // Jestliže i není null, nastav j na i. Jinak (pokud i je null), nastav j na 0.

C# 3.0

Vyšel na konci roku 2007 společně s .NET Frameworkem 3.5 a Visual Studiem 2008. Obsahuje poměrně revoluční změny, které však nevyžadují změnu podkladového IL, takže aplikace v něm psané půjdou spouštět i na počítačích vybavených toliko druhým Frameworkem, ponesou-li si s sebou patřičné knihovny.

LINQ

Language Integrated Query, tedy integrovaný dotazovací jazyk přináší nový způsob pro dotazování nad jakýmikoliv daty, usnadňuje jejich tvorbu, třídění a vyhledávání v nich. LINQ to Objects umožňuje dotazování nad normálními objekty (respektive jejich kolekcemi), LINQ to SQL přináší nový způsob pro práci s databázemi a LINQ to XML umožňuje pracovat s XML soubory. Následující příklad ukazuje dotaz LINQ který nám ze zdrojového pole vrátí druhé mocniny všech lichých čísel a výsledky seřadí sestupně. Všimněte si podobnosti se syntaxí SQL.

int[] myArray = { 1, 5, 2, 10, 7 };
 
IEnumerable<int> query = from x in array //Požadujeme všechny elementy z pole myArray,
                         where x % 2 == 1//kde zbytek po celočíselném dělení (modulo) je roven 1
                         orderby x descending//výsledek požadujeme seřazen sestupně
                         select x * x;//a vrácená číla umocníme na druhou
// Výsledek : 49, 25, 1

Lambda výrazy

Pomocí lambda výrazů, jež si berou inspiraci z funkcionálního programování, je možné tvořit anonymní metody, které obsahují jeden výraz nebo několik příkazů a použít je v situaci, kdy je očekávána instance delegáta. Pro potřebu lambda výrazů byl do C# 3.0 uveden nový operátor =>. Ten se nazývá „přechází v“.

V C# 2.0 bychom vyhledávání prvků v seznamu pomocí anonymní metody napsali například takto:

List<int> poleCisel = new List<int> { 1, 2, 3, 4, 5 };
List<int> vysledek = poleCisel.FindAll(delegate(int i)
{
     return i < 4;
});

A ta samá funkčnost napsaná pomocí lambda výrazu v C# 3.0:

 
List<int> poleCisel = new List<int> { 1, 2, 3, 4, 5 };
List<int> vysledek = polecisel.FindAll(i => i < 4);

Všimněte si, že se neuvádějí typy argumentů (tedy že i je Integer), ale podobně jako u klíčového slova var je typ argumentu odvozen v době kompilace (tedy ne za běhu, takže je stále dodržena typová bezpečnost) odvozen z kontextu.

Obecně tedy lambda výraz zapisujeme jako (vstupní argumenty) => výraz.

Inicializátory objektů a kolekcí

Zakaznik  z = new Zakaznik(); 
z.Jmeno = "Petr";

Můžeme zkráceně zapsat jako:

Zakaznik z = new Zakaznik { Jmeno="Petr" };

Zápis inicializace kolekcí pak můžeme také zkrátit z původního

MujSeznam  seznam = new MujSeznam();
seznam.Add(1);
seznam.Add(2);

na zkrácené:

MujSeznam seznam = new MujSeznam { 1, 2 };

Za předpokladu, že naše třída MujSeznam implementuje rozhraní System.Collections.Ienumerable a má veřejnou metodu Add.

Rozšiřující metody

Pomocí rozšiřujících metod můžeme vyvolat dojem, že třída má metody, které jsou ve skutečnosti zapsány mimo tuto třídu. Rozšiřující motedy jsou ve skutečnosti statické metody, které se dají volat jako metody instance. Následující příkaz ukazujeme jak můžeme rozšířit třídu string o novou metodu, kterou deklarujeme v oddělené třídě StringExtensions. Na jakékoliv instanci třídy string poté můžeme volat naši novou metodu.

public static class StringExtensions
{
    public static string Left(this string s, int n)
    {
        return s.Substring(0, n);
    }
}
string s = "foo";
s.Left(3); // Stejné jako as StringExtensions.Left(s, 3);

Klíčové slovo var

Dictionary<string, List<float>> x = new Dictionary<string, List<float>>();

Můžeme nyní zapsat jako

var x = new Dictionary<string, List<float>>();

Typ proměnné x bude určen podle pravé strany výrazu a to již v době překladu. To není jen zkrácení zápisu pro inicializaci proměnných, ale jde o formu zápisu, která se používá při deklaraci proměnných anonymních typů.

Výrazové stromy

Expression Trees, neboli Výrazové stromy umožňují pracovat s kódem nejen jako se spustitelnými příkazy, ale také jako s daty. Můžeme tedy v aplikaci vytvořit stromovou strukturu reprezentující kód. U té pak můžeme sledovat její veřejné vlastnosti a na základě toho ji analyzovat, zjistit všechny potřebné informace, popřípadě ji optimalizovat. V případě potřeby ji můžeme dále zkompilovat do spustitelné podoby pomocí metody compile.

Anonymní třídy

Anonymní třídy umožňující např. rychlé vytvoření objektů přenášejících informace vyžádané z databáze přes LINQ.

C# 4.0

Tato verze je oficiálně ve vývoji od října 2008, novinky byly ohlášeny na Microsoft Professional Developers Conference 2008. Datum vydání není zatím známé, ale jistě vyjde dohromady s .NET Frameworkem 4.0 a Visual Studiem 2010. Nová verze se zaměřuje hlavně na spolupráci s dynamickými aspekty programování a frameworky, jako například DLR a COM. Mezi další novinky patří:

„Ahoj, světe!“

Následující jednoduchá konzolové aplikace vypíše „Ahoj, světe!“ na standardní výstup.

using System;
 
namespace MojeKonzolováAplikace
{
  class HlavníTřída
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Ahoj, světe!");
    }
  }
}

Rozeberme krátce jednotlivé příkazy. Třídy, základní jednotky objektového programování, jsou v C# rozděleny pro lepší orientaci a jednoznačnost názvů do jmenných prostorů. Na počátku zdrojového kódu jmenujeme příkazem using jmenné prostory, jež budeme používat — nebudeme pak muset rozepisovat jejich název, všechny třídy z nich jsou nám hned přístupny.

Na dalším řádku příkazem namespace říkáme, že chceme zařadit kód vymezený následujícími složenými závorkami do jmenného prostoru MojeKonzolováAplikace. Hned poté definujeme klíčovým slovem class třídu Hlavní třída, její obsah bude opět vymezen dalšími složenými závorkami. Kód není nutné odsazovat (bílé znaky se ignorují), jen je to praktické.

Všimněme si také, že identifikátory mohou obsahovat písmenka s háčky a čárkami — je tomu tak již od prvních verzí jazyka.

Překladač hledá při vytváření spustitelného souboru vstupní bod aplikace. Musí se jednat o statickou metodu nevracející žádnou hodnotu nebo typ int (celé číslo), která buď nepřebírá žádné argumenty, nebo pole řetězců (stringů) a která se jmenuje Main. Deklaraci takové metody vidíme na dalším řádku programu. Klíčové slovo static značí statickou metodu, tedy takovou část kódu, kterou je možno volat bez vytvoření instance třídy. Klíčové slovo void značí, že metoda nic nevrací.

Argumenty metody se vypisují do obyčejných závorek za její název. Podobně jako při deklarování proměnných se nejdříve uvádí typ proměnné (string[]) a pak její název (args). Pole značíme dvojicí hranatých závorek za názvem typu.

Tělo metody tvoří jediný řádek ukončený středníkem. Volá statickou metodu třídy Console (sídlí ve jmenném prostoru System) jménem WriteLine, která za argument pojímá jedinou proměnnou typu string, kterou vypíše uživateli do konzole. Řetězce se ohraničují počítačovými uvozovkami.

Vývojová prostředí

XML Dokumentace

Systém dokumentace kódu je podobný JavaDoc, používanému v jazyce Java. Významným rozdílem je ale to, že je založen na XML. Následující příkaz ukazuje komentář k metodě.

public class Foo
{
    /// <summary>Popis metody.</summary>
    /// <param name="firstParam">Popis parametdu metody</param>
    /// <returns>Popis návratové hodnoty metody</returns>
    public static bool Bar(int firstParam) {}
}

Jak vidíme, každý řádek komentáře musí začínat řetězcem "///". Tyto komentáře často používají nástroje jako IntelliSense integrovaný v Microsoft Visual Studiu, který programátorovi při psaní kódu napovídá.

Název jazyka

Název jazyka C# je odvozen z hudební notace, kde křížek označuje zvýšení noty o půl tónu a v tomto případě by označoval notu cis, tedy C zvýšené o půl tónu. Podobně vznikl název jazyka C++ jako zlepšení jazyka C : "++" totiž v syntaxi jazyka C znamená zvýšení hodnoty proměnné o 1.

Křížek na počítačové klávesnici (#) a křížek v hudební nauce (♯) jsou dva odlišné znaky. Pro zápis názvu jazyka C Sharp se nepoužívá znak hudebního křížku z technických důvodů, protože tento se na standardní klávesnici nevyskytuje, ale pro zjednodušení se používá klasický křížek. Toto je zakotveno ve specifikaci jazyka C#, ECMA-334. Jak jsme již řekli, toto opatření je spíše praktického rázu, takže v případech jako jsou různé marketingové materiály se často používá znak křížku z hudební notace.

Reference

  1. http://www.ecma-international.org/publications/standards/Ecma-334.htm Standard C#
  2. Anonymous Methods (C#)
  3. Operator (C# Reference). Microsoft. Dostupné online.

Externí odkazy