C Sharp

A C# (kiejtése: szí-sárp, de ismert a cisz elnevezés is) a Microsoft által a .NET keretrendszer részeként kifejlesztett objektumorientált programozási nyelv. A nyelv alapjául a C++ és a Java szolgált.

Története

Előzmények 
A 90-es években a Microsoft a saját Java keretkörnyezetét a saját operációsrendszer-specifikus függvényeivel és szolgáltatásaival bővítette ki, amire viszont nem volt engedélye (a Java licencét birtokló) Sun Microsystemstől. A Microsoft-féle Javára fejlesztett alkalmazások nem lettek volna futtathatók más rendszereken, ami ellenkezik a Java platform-függetlenségre vonatkozó alapelvével. A Sun végül beperelte a Microsoftot, és ezt követően a Microsoft a Java eltávolítására kényszerült a Windows rendszerekből (természetesen a Java-t a továbbiakban is lehet külön rendszerként telepíteni). A Microsoft egy saját keretrendszer fejlesztésébe kezdett. Ez lett a .NET (kiejtése: dotnet), és ehhez a keretrendszerhez adták ki programnyelvként a C# első verzióját. A későbbiekben ezt a nyelvet úgy fejlesztették tovább, hogy meglegyen az egyensúly a programozó nyelvi szabadsága és a gyors alkalmazásfejlesztés lehetősége között. Rengeteg hivatalosan kiadott bővítmény létezik hozzá, amelyek a kódolást könnyebbé teszik.

A C# fejlesztését Anders Hejlsberg vezette, aki a Turbo Pascal tervezője is volt. A .NET osztálykönyvtárait a programozók eredetileg egy sajátos, ún. SMC (Simple Managed C) nyelven írták. 1999-ben azonban Hejlsberg (aki addig a J++ nyelven dolgozott) vezetésével egy csapat alakult egy új programozási nyelv létrehozására, akkoriban COOL (C-like Object Oriented Language, magyarul: C-szerű Objektum Orientált Nyelv) fedőnév alatt. A cél egy olyan nyelv megalkotása volt, mellyel teljesen objektumorientált módon lehet a keretrendszer komponenseit fejleszteni. Egy évvel később, 2000 júliusában a PDC konferencián a .NET-tel, és az ASP.NET-tel együtt a C#-ot is bemutatták, immár ezen névvel, hogy az esetleges szerzői jogi problémákat megelőzzék. Bár sok bírálat érte megjelenésekor, főleg a Java-s táborból, miszerint a Microsoft pusztán legyártotta a saját Java verzióját, Anders azt nyilatkozta, hogy a nyelvet sokkal inkább a C++-hoz szerették volna közelíteni.

Verziók

Szabványosítás 
A Microsoft benyújtotta a C# nyelvi specifikációját az ECMA-hoz formális szabványosításra. 2001 decemberében az ECMA kiadta az ECMA-334 C# Language Specification szabványt, 2003-ban pedig ISO szabvány lett (ISO/IEC 23270). Több független megvalósítás is folyamatban van, többek között:

 Mono, a Ximian nyílt forráskódú .NET implementációja
 dotGNU és a Portable.NET a Free Software Foundationtól
Bár a Mono Project egy nagyrészt kompatibilis nyílt forráskódú C# fordítót állított elő (lehetővé téve az ilyen kódok futtatását Linux és Macintosh rendszereken), a nyelv Windows operációs rendszereken kívüli használata nem terjedt el, mivel az osztálykönyvtárakat szolgáltató .NET Framework portolása más rendszerek alá még kezdetleges stádiumban van. Ugyanakkor a Mono az utóbbi években rohamos fejlődésnek indult, amit elősegített a Microsoft és a Novell (a Mono „anyacége”) együttműködése a Microsoft Silverlight technológiájának Linux illetve Macintosh rendszerekkel kompatibilis változatának – a Moonlightnak – a készítésekor.

Áttekintés 
A C# az a programozási nyelv, ami a legközvetlenebb módon tükrözi az alatta működő, minden .NET programot futtató .NET keretrendszert, valamint erősen függ is attól: nincsen nem menedzselt, natív módban futó C# program. A primitív adattípusai objektumok, a .NET típusok megfelelői. Szemétgyűjtést használ, valamint az absztrakcióinak többsége (osztályok, interfészek, delegáltak, kivételek…) a .NET futtatórendszert használja közvetlen módon.

A C vagy C++ nyelvhez hasonlítva a C# több korlátozást és továbbfejlesztést is tartalmaz. A lehetőségei közül néhány:

 A mutatók és a nem ellenőrzött aritmetika csak egy speciális, nem biztonságos módban (unsafe mode) használható. A legtöbb objektum-hozzáférés csak biztonságos hivatkozásokon keresztül tehető meg, és az aritmetikai műveletek debug módban túlcsordulás szempontjából ellenőrzöttek.
 Az objektumok nem szabadíthatók fel közvetlen módon, ehelyett a szemétgyűjtő szabadítja fel őket, mikor már nincs rájuk hivatkozás. Ez a módszer kizárja a nem létező objektumokra való hivatkozás lehetőségét.
 A destruktorok (~) elérhetőek. A megfelelően megírt IDisposable interfész (Disposable programozási minta), aminek a lefutását garantálja using blokk, együtt kikényszerítheti az azonnali felszabadítást az osztályon belüli natív erőforrások esetében. A nem natív erőforrások felszabadítását ebben az esetben is a szemétgyűjtő (Garbage Collector) végzi. A finalizerek szintén rendelkezésre állnak, de nem váltanak ki azonnali felszabadítást. Finalizer a Dispose eljárás javasolt implementációs módozatában nem fut le, mivel az ajánlás szerint a szemétgyűjtőt utasítani kell a finalizer hívás kihagyására.
 A nyelv csak egyszeres öröklődést támogat, de egy osztály több interfészt is megvalósíthat.
 A C# sokkal típusbiztosabb, mint a C++. Az egyetlen implicit konverzió a biztonságos konverzió, úgy mint az egészek tágabb intervallumba konvertálása vagy a leszármazott osztályok alaposztályba konvertálása. Nincs implicit konverzió az egészek és a logikai típus (boolean) között, a felsorolás tagok és az egészek között. Nincsenek void mutatók (bár az Object osztályra mutató mutatók hasonlóak), valamint bármely, a felhasználó által definiált implicit konverziót explicit módon meg kell jelölni.
 A felsorolás adattagjai a saját névterükben helyezkednek el.
 A 2.0-s verziótól felfelé már rendelkezik a generikus programozás néhány eszközével.
 Tulajdonságok (Properties) használhatók, amelyek úgy tesznek lehetővé kódfuttatást mezők beállításakor és olvasásakor, hogy közben az adattagok szintaxisát használja.

Összehasonlítás a Javával 
A Microsoft bár úgy fejlesztette ezt a nyelvet, mint a saját Java implementációját, bizonyos tulajdonságokban azonban eltérő szemléletmódot követ a két rendszer. Ilyen különbségek például:

 A Java alapértelmezett láthatósága mindig csomagon (package) belül publikus, a C#-nál mindig privát, a protected jelentése eltér, illetve támogatja az internal és a protected internal láthatóságot
 A C# támogatja a parciális osztályokat (2.0-s verziótól felfelé), és az operátor-felüldefiniálást (:en:Operator Overloading)
 A metódusok a Javában alapból virtuálisak, ellentétben a C#-pal
 A Java ellenben például lehetővé teszi a fordításidejű kivételkezelést
 A Java támogatja az egzisztenciális generikusokat, míg a C# a ko- és kontravarianciát (4.0-s verziótól) a generikusoknál
 A C# támogatja az azonos nevű, de eltérő verziójú szerelvények betöltését, ezzel szemben a Java-ban nincs ilyen támogatás
 Java esetén nincsenek tulajdonságok, amelyek megkönnyítenék az objektumok belső változóinak az ellenőrzött lekérését és módosítását. Helyette ez a funkció Getter és Setter metódusokkal van megvalósítva.
 A C# támogatja a delegált metódusokat, amely hasonló funkciót valósít meg, mint C++ esetén a függvény mutatók.
 A C# a delegált metódusoknak köszönhetően támogatja az eseménykezelést
 A C# esetén van unsafe (nem biztonságos) kontextus, amelyben létezik mutató típus. (optimalizációt segíti)
 A C# esetén van unchecked (nem ellenőrzött) kontextus, amiben a változók túlcsordulása és helyes típus konvertálása felülbírálható (optimalizációt segíti)

Szintaxisban a két nyelv ugyanabba a nyelvcsaládba (C/C++ alapú nyelvek) tartozik, tehát mindkettőre a kapcsos zárójeles tagolás, sor végi pontosvessző a jellemző, ezért a kód nagyban hasonlít.

Kódkönyvtárak 
A legtöbb programozási nyelvtől eltérően a C# megvalósítások nem rendelkeznek önálló, eltérő osztály- vagy függvénykönyvtárakkal. Ehelyett a C# szorosan kötődik a .NET keretrendszerhez, amitől a C# kapja a futtató osztályait és függvényeit. A .NET keretrendszer osztálykönyvtárat tartalmaz, ami a .NET nyelvekből felhasználható egyszerű feladatok (adatreprezentáció és szövegmanipuláció) végrehajtásától kezdve a bonyolult (dinamikus ASP.NET weblapok generálása, XML feldolgozás és reflexió) feladatokig. A kód névterekbe van rendezve, mely a hasonló funkciót ellátó osztályokat fogja össze. Például System.Drawing a grafikai, System.Collections az adatstruktúra és System.Windows.Forms a Windows ablakos megjelenítéséért felelős funkciókat fogja össze.

További rendezési szint az assembly (szerelvény). Egy assembly állhat egy fájlból, vagy több összelinkelt fájlból (az al.exe segítségével), ami több névteret és objektumot tartalmazhat. A különböző feladatokhoz szükséges osztályokat assemblyk (például System.Drawing.dll, System.Windows.Forms.dll) hivatkozásával vagy a központi könyvtár (mscorlib.dll a Microsoft megvalósításában) használatával érhetik el a programok.

A .NET keretrendszer támogatja azonos nevű, de eltérő verziójú assemblyk betöltését, amelyek verziózott implementációkat tartalmazhatnak, így könnyedén lehetővé válik egy alkalmazáson belül a visszafelé kompatibilitás eltérő implementációk betöltésével és példányosításával.

Példaprogramok 
Egy egyszerű C# program:
public class ExampleClass
{

    public static void Main()
    {
        System.Console.WriteLine("Helló világ!");
    }

}

A program megjeleníti a Helló világ! szöveget a konzolon. A program részletei a következők:

public class ExampleClass

Ez az osztálydeklaráció. Publikus, azaz bármely más projekt szabadon használhatja az osztályt. Az összes információ a kapcsos zárójelek között az osztály leírását szolgálja. Minden programban kötelező legalább egy osztályt implementálni, itt ennek neve ExampleClass lett.

public static void Main()

Ez a függvény a program belépési pontja, ahol a program végrehajtása megkezdődik, mindig a Main() nevet viseli.

System.Console.WriteLine("Helló világ!");

Ez a rész felel meg a feladat végrehajtásának. A Console egy rendszerobjektum, ami egy parancssort jelképez. A Console objektum WriteLine metódusának meghívása a paraméterként átadott szöveget kiírja a parancssorba.

Változók és deklarációk 
Ahhoz, hogy értékeket tudjunk megadni, először változót kell deklarálni, és utána inicializálni azt.
deklaráció: int x;
inicializálás: x = 10;
Ezt lehet egyszerre is: int x = 10;

Egy példa a változókra:
class Változók                           // A nyelv támogatja az Unicode-karakterek használatát, így pl. ékezetek is tehetők a nevekbe.
{

    public static void Main()
    {
        int i = 10;                      // Az egész típusú i változó értéke 10.
        System.Console.WriteLine(i);     // Kírjuk a képernyőre.

        int i2 , i3;                     // Többszörös deklarálás
        i2 = 12;                         // Inicializáció
        i3 = 13;
        Console.WriteLine(i2);
        Console.WriteLine(i3);

        const double állandó = 3.1415;   //Egy állandó deklarációja és inicializálása
        double d = 12.3;                 //Tizedestört
        float f = 0.65F;                 //Az F betűvel jelezzük, hogy lebegőpontosan ábrázolandó.

        char c = 'c';                    // A char 1 karaktert tud tárolni (és azt ' ' jelek között kell megtenni).
        string s = "Helló világ!";       // A string karaktersorozatot tud tárolni "" jelek között.
        Console.WriteLine("double: {0}, float: {1}, char: {2}, string: {3}, állandó: {4}",d,f,c,s,állandó); //kiírjuk a képernyőre az eredményeket. A {0} helyére a d, az {1} helyére az f... fog kerülni.
        Console.ReadKey();               // A program egy billentyű lenyomására vár,
                                         //tehát nem fog véget érni a programunk, míg meg nem nyomunk egy gombot.
    }

}

Operátorok

Matematikai 

Az operátorok műveletek: +, -, *, /, %(maradékképzés). A C++-ban bevezetett jelölések itt is léteznek, tehát például:

i = i+1; ez ugyanaz, mint ez: i++;

i = i+d; ez ugyanaz, mint ez: i += d;

i = i*d; ez ugyanaz, mint ez: i *= d;...

Relációs:
Relációs jelek segítségével két érték között végezhetünk viszonyításokat. pl: < (kisebb) > (nagyobb), <= (kisebb vagy egyenlő) >= (nagyobb  vagy egyenlő), != (nem egyenlő), == (egyenlő) ...

példa:
...
        int x = 10;
        int y = 23;
        Console.WriteLine(y < x);  // kiírja, hogy false (hamis)
        Console.WriteLine(y == x); // hamis
        Console.WriteLine(y != x); //true (igaz)
        Console.WriteLine(x <= y); // x kisebb (vagy egyenlő) mint y: igaz
        Console.ReadKey();
...

Logikai / feltételes 

A logikai műveletek is elérhetőek hasonlóan a kiinduló nyelvekhez:
 && : és
 || : vagy
 ! : negáció
 stb.

példa:
...
        bool igaz = true;   // Az igaz nevű változó értéke igaz.
        bool hamis = false; // A hamis nevűé hamis.
        if( igaz == false || hamis == false ) // Ha az igaz hamis vagy a hamis hamis, akkor kiírja a szöveget.
        {
            System.Console.WriteLine("Az egyik jó volt.");
        }
...
A && balról jobbra haladva kezdi kiértékelni a vele összekapcsolt kifejezéseket, és ha olyat talál, ami hamis, akkor a többit már ki sem értékeli, hiszen a teljes kifejezés értéke most már biztosan hamis lesz. Ugyanígy ha a || elér egy igaz kifejezéshez, tovább már nem értékel, mert itt már biztos, hogy a teljes kifejezés igaz lesz.

Vezérlési szerkezetek

Elágazások (szelekciók) 
Az elágazás valamilyen feltételtől függő tevékenység végrehajtását jelenti. Két alapvető fajtája van: a kétágú és a többágú szelekció. Kétágú szelekció esetén (if, else) a program futása vagy az igaz vagy a hamis ágon folytatódik. Többágú szelekciónál lehetőség van egy kifejezés eredményének több lehetséges állapotától függő tevékenység elvégzésére.

Példa:
...
        Console.WriteLine("Adjon meg egy számot:");
        int x = Convert.ToInt32(Console.ReadLine()); // bekérünk egy egész típusú számot, ha nem egész típusú, akkor is az lesz, mert átkonvertáljuk.

        switch(x) // vizsgáljuk az x-et
        {
            case 17: // ha 17
                Console.WriteLine("x == 17");
                break; // kilépünk a switchből
            case 10: //ha 10
                Console.WriteLine("x == 10");
                break; // kilépünk
            default: // ha egyik sem
                Console.WriteLine("Default");
                break; // kilépünk
        }
...

Ciklusok (iterációk) 
Amikor egy adott utasítás vagy utasítássorozatot többször kell elvégeznünk akkor ciklust használunk, például: ki kell írni a konzolra 0-100-ig a számokat. A ciklusoknak alapvetően három típusa létezik: a számlálásos, az elöltesztelős és a hátultesztelős. A számlálásos ciklus egyik megvalósítási formája a for ciklus:
        for(int i = 0; i <= 100; i++) //addig fog ismétlődni a ciklus, amíg az i el nem éri a 100-at
        {
            System.Console.WriteLine(i);
        }

Elöltesztelős ciklus a while kulcsszóval érhető el:

        int i = 0;         //kezdőérték beállítása
        while( i <= 100 )  // ciklusfeltétel megadása
        {
            System.Console.WriteLine(i);
            i++; //ciklusváltozó növelése
        }

Hátultesztelős a do-while párossal:
        do
        {
            Console.WriteLine("Adjon meg két számot:");
            int egyik = Convert.ToInt32(Console.ReadLine());
            int másik = Convert.ToInt32(Console.ReadLine());

            int eredmény = egyik + másik;
            Console.WriteLine("Az összeguk: {0}", eredmény);

            Console.WriteLine("Ha ki akar lépni, üsse be, hogy kilépés, ha nem, akkor azt, hogy vissza!");
            választás = Convert.ToString(Console.ReadLine());

        }
        while (választás != "kilépés"); // Ha nem a kilépés szót írjuk be, újrakezdődik a ciklus.

Létezik a C#-ban még egy különlegesebb ciklusvezérlő, ez a foreach. Egy adott tömb, vagy lista elemein megy végig, a különlegessége, hogy nem kell megadni kilépési pontot, sem feltételt, egyszerűen akkor marad abba, ha a végére ér az adott adatstruktúrának. Használata javasolt, mivel írásmódja szebb, mint a hagyományos for ciklusé, és a belőle forduló kód a legtöbb esetben optimálisabb CIL kódot eredményez a többi módszerhez képest.
Példa:
...
        int[] számok = new int[7]{1,3,2,5,7,4,9};
        int páros = 0;
        int páratlan = 0;

        foreach( int i in számok )
        {
            if (i % 2 == 0) páros++;
            else páratlan++;
        }
...

Felsorolástípus (enum) 
A felsorolás típust akkor szoktuk használni, ha sok elemet akarunk megadni. Ez az összegyűjtés (enumeration) magától megszámozza az elemeket 0 -...-ig, de ha saját számozást akarunk, akkor magunk is megszámozhatjuk. Például:

class EnumClass
{
    enum színek{piros, kék, zöld, sárga};

    public static void Main()
    {
        System.Console.WriteLine(színek.zöld); // kiírja a színt

        //ciklus a színeken történő végighaladásra
        for( színek i = színek.piros; i <= színek.sárga; i++)
        { // i = piros, piros kisebb és egyenlő sárga ( piros<kék<zöld<sárga )
            System.Console.WriteLine(i);
        }
        System.Console.ReadKey();
    }
}

Tömbök 
A tömb az az adattípus, amikor egy adott típusú változóból egy sorozatot, vektort vagy mátrixot készítünk. Általános szintaxis: Típus[] változónév = new Típus[hossz];. Például:

class Tömbök1
{
    public static void Main()
    {
        int[] számok = new int[5] {1, 3, 6, 3, 2}; // létrehozunk egy tömböt és utána megadjuk az elemeit
        int[] számok2;
        számok2 = new int[] {3, 6, 1, 6, 8, 3}; // az elemek számából magától kiszámolja, hogy hány elemű...

        string[] karakterlánc = new string[3] {"egy", "kettő", "harom"};

        Console.WriteLine("A számok tömb 5. elemének értéke: {0}", számok[4]);
        Console.WriteLine("A számok2 tömb 3. elemének értéke: {0}", számok2[2]);
        // a tömbök indexelése 0-tól kezdődik, így a 4. indexű elem a tömb 5. eleme

        // ciklus, mely végighalad a tömb elemein:
        for( int i = 0; i < karakterlánc.Length; i++ ) Console.WriteLine(karakterlánc[i]);
        Console.ReadKey();
    }
}
A System.Collections.Generic névtér további adatszerkezeteket tartalmaz, amelyek bizonyos célokra hasznosabbak, mint a tömbök:
 Sorozat (Queue): egyszerű FIFO-adatszerkezet
 Verem (Stack): egyszerű LIFO-adatszerkezet
 Lista (List): hasonlít a tömbhöz, de nincs előre definiált mérete
 Halmaz (HashSet): hasonlít a listához, de az elemeknek nincs sorrendje, és egy elem legfeljebb egyszer szerepelhet benne
 Szótár (Dictionary): kulcs-érték párok halmaza

OOP-programozás (objektumorientált) 
class OOP
{
    public int x; //publikus elérésű egész x
    private int y; //private, tehát nem lehet elérni másik osztályból
    public int Y   //itt egy tulajdonság, mely tulajdonságot ad az y private változónak, hogy el lehessen érni
    {
        get  { return y; }
        set  { y = value; }
    }
}

class ÚjOsztály // egy másik osztály
{
    public static void Main()
    {
        OOP származtat = new OOP(); // származtatunk az OOP osztályból, hogy elérhessük annak az osztálynak a tartalmát
        származtat.x = 17;  // az OOP osztály x változója = 17
        származtat.Y = 18;  // a set blokkon keresztül értéket adunk az Y-nak és aztán azt az értéket visszaadjuk a get blokk segítségével az y-nak
        Console.WriteLine("x = {0}, y = {1}", származtat.x, származtat.Y); // x = 17, y = 18
        Console.ReadKey();
    }
}

Osztályok láthatósága a C#-ban (zárttól a nyitott felé):
 private: nem lehet elérni másik osztályból. Alapesetben minden osztály, metódus, stb. ilyen.
 protected: származtatott osztályból érhető el.
 internal: azonos assembly-ből elérhető
 protected internal: fenti két csoport uniója
 public: bárhonnan elérhető

Struktúra 
A struktúra egy másik adatszerkezet a nyelven belül, mely nagyban hasonlít az osztályra. A fő különbség az, hogy míg az osztályok példányait referenciaként kezeli a nyelv, a struktúrapéldányokat érték szerint. Ez akkor válik nyilvánvalóvá, amikor pl. egyedet másolunk. Ha objektumról (osztályról) van szó, és a másolatban megváltoztatunk egy adott adattagot (módosítunk/felülírunk egy struktúrapéldányt vagy felülírunk egy osztálypéldányt), akkor az a tulajdonság az eredeti egyedben is megváltozik. Ellenben, ha struktúráról beszélünk, akkor másolatnál egy teljesen új memóriaterületre íródik le az új adattag, ezért ha azt meg is változtatjuk, az az eredetit nem befolyásolja.

struct struktúra_1
{
    public int kor;
    private string név; // mivel private, létre kell hoznunk egy értékadó tagfüggvényt.
    public string Név
    {
        get return név;
        set név = value;
    }
}

public class struktúra_használ
{
    public static void Main()
    {
        struktúra_1 adatok = new struktúra_1(); // példányosítunk
        adatok.kor = 14;
        adatok.Név = "Kovács István";
        Console.WriteLine("Az életkorom: {0}, a nevem: {1}", adatok.kor, adatok.Név);
        Console.ReadKey();
    }
}

Egy másik különbség, hogy struktúráknak nem adhatunk meg paraméter nélküli konstruktort, automatikusan generálódik hozzá egy. Amennyiben fontos számunkra a struktúra érvényessége, készíthetünk hozzá ellenőrző metódust.

Egy különleges alkalmazási formája a csak olvasható struktúra, amelyek használata javasolt elemi, adattároló struktúrák esetén.

Nullable referencia típusok 
A C# 8.0 legnagyobb újdonsága a Nullable referencia típusok, ami kicsit félrevezető név. A referencia típusok eddig is felvehettek null értéket. Ha azt nem kezeltük le, hogy egy referencia null értéket is felvehet és úgy próbáltunk rajta metódust hívni, vagy tulajdonságot lekérdezni/írni, akkor NullReferenceException típusú kivételt kaptunk.

Ez pedig sajnos a "legnépszerűbb" futásidejű hiba típussá nőtte ki magát az elmúlt jó pár évben. Ez alatt az értendő, hogy a fejlesztők leginkább ilyen kivételekkel találkoznak fejlesztés közben, ha nem jól írják meg a kódjukat.

Ebben hivatott segíteni a Nullable reference types bevezetése. Ez a gyakorlatban azt jelenti, hogy a ? operátort ki kell tennünk referencia típusok esetén, ha azt szeretnénk jelezni, hogy az a változó megengedett, hogy null értéket vegyen fel.

Ebben az esetben, ha elmulasztjuk a null ellenőrzést, akkor már fordítási idejű figyelmeztetést kapunk.

Ha pedig nem jeleztük, hogy a változó null értéket is felvehet, akkor a fordító a változót úgy fogja kezelni, mint ami referencia, de normál körülmények között nem lenne szabad neki null értéket felvennie. Ebben az esetben a null check elmulasztása szintén fordítási idejű figyelmeztetést fog generálni.

Jegyzetek

További információk 
 
 Java és C# különbségek
 Dr. Sipos Marianna: Programozás élesben - C#, INFOKIT kiadó, 2004, 
 
 Programozni egyszerű! Programozás alapjai kezdőknek C# nyelven  
 C# programozási nyelv - parancsok-operátorok listája, egyszerű összehasonlítás további nyelvekkel.
 CSharp tutorial 

Imperatív programozási nyelvek
Objektumorientált programozási nyelvek
Microsoft
C Sharp-kódpéldák