C sharp

**C#** (lausutaan ”si sharp”) on Microsoftin kehittämä yleiskäyttöinen, korkean tason ohjelmointikieli, joka tukee useita ohjelmointiparadigmoja, kuten oliopohjaista, imperatiivista, funktionaalista, geneeristä ja komponenttipohjaista ohjelmointia. Kieli on olennainen osa .NET-ekosysteemiä ja sitä käytetään laajasti sekä Microsoftin omissa että avoimen lähdekoodin toteutuksissa, kuten .NET-, Mono- ja Unity-ympäristöissä.

Kielessä on staattinen ja vahva tyypitys, automaattinen muistinhallinta roskienkeruun avulla sekä suoritusmalli, jossa lähdekoodi käännetään ensin välitasokoodiksi (Common Intermediate Language, CIL) ja suoritetaan sen jälkeen tyypillisesti ajonaikaisen kääntämisen (just-in-time, JIT) tai ennen ajoa tehtävän kääntämisen (ahead-of-time, AOT) kautta. Kieli on suunniteltu moderniksi ja turvalliseksi vaihtoehdoksi C-suvun kielille, säilyttäen samalla monia C++- ja Java-kielistä tuttuja syntaksisia elementtejä.

C#:llä kehitetään muun muassa yrityssovelluksia, verkkosovelluksia ja -palveluita, pilvipohjaisia ratkaisuja (Microsoft Azure), työpöytä- ja mobiilisovelluksia (.NET MAUI), pelejä (Unity), selainpohjaisia sovelluksia (Blazor) sekä data- ja tekoälysovelluksia (ML.NET). Uusin vakaa versio on C# 14.0, joka julkaistiin marraskuussa 2025 osana .NET 10 -alustaa.

## Historia
### Tausta ja synty
1990-luvun lopussa Microsoft aloitti .NET-hankkeen yhtenäisen sovelluskehitysalustan luomiseksi. Hankkeen puitteissa aloitettiin uuden C#-ohjelmointikielen kehitys pääsuunnittelija Anders Hejlsbergin johdolla. Kieli esiteltiin julkisesti vuonna 2000 osana .NET Framework -alustaa ja Visual Studio .NET -kehitysympäristöä.

Microsoft toimitti kielen ja siihen liittyvän Common Language Infrastructure (CLI) -spesifikaation standardoitavaksi Ecma Internationalille. Kielestä tuli Ecma-standardi ECMA-334 joulukuussa 2002 ja myöhemmin ISO/IEC-standardi ISO/IEC 23270. Standardointi helpotti vaihtoehtoisten toteutusten, kuten avoimen lähdekoodin Mono-projektin, kehittämistä.

Kielen nimi ”C#” viittaa ohjelmointikielten C-sukuun ja musiikin *korotettuun säveleen (C♯)*. Virallisissa yhteyksissä nimi kirjoitetaan risuaitamerkin (#) kanssa ECMA-standardin mukaisesti (”C#”).

### Varhaiset versiot (1.0–4.0)
Ensimmäinen C#-versio (1.0) julkaistiin vuonna 2002 osana .NET Framework 1.0 -alustaa ja Visual Studio .NET -kehitysympäristöä. Versio tarjosi oliopohjaiset perusrakenteet, kuten luokat, rakenteet, rajapinnat, poikkeuskäsittelyn, ominaisuudet, tapahtumat ja delegaatit, sekä erottelun viite- ja arvotyyppien välillä. Kieli perustui automaattiseen roskienkeruuseen Common Language Runtime (CLR) -ympäristössä.

C# 2.0 julkaistiin vuonna 2005 .NET Framework 2.0 -version yhteydessä. Versiossa esiteltiin geneeriset tyypit ja menetelmät, nullable-arvotyypit, anonyymit metodit, iteraattorit (*yield return*), osittaiset tyypit sekä staattiset luokat. Geneerisyys toteutettiin CLR-tasolla ilman tyyppien poistoa (*type erasure*), mikä paransi suorituskykyä ja tyyppiturvallisuutta.

C# 3.0 julkaistiin vuonna 2007 .NET Framework 3.5 -alustan mukana. Versio keskittyi kielen ilmaisukyvyn parantamiseen ja LINQ-kyselyjen tukemiseen. Uusia ominaisuuksia olivat lambda-lausekkeet, paikallisen tyypin päättely (*var*), anonyymit tyypit, laajennusmetodit, kyselylausekerakenne sekä ilmaisupuut (*expression trees*).

C# 4.0 julkaistiin vuonna 2010 .NET Framework 4 -alustan yhteydessä. Versio toi dynaamisen sidonnan (*dynamic*), nimetyt ja valinnaiset parametrit sekä parannetun kovarianssin ja kontravarianssin geneerisille rajapinnoille ja delegaateille. Ominaisuudet helpottivat yhteentoimivuutta dynaamisten kielten ja COM-komponenttien kanssa.

### .NET Core ja avoimen lähdekoodin vaihe
Vuosina 2012–2015 julkaistut C# 5.0 ja C# 6.0 keskittyivät kielen ilmaisukyvyn ja käytettävyyden parantamiseen. C# 5.0 (2012) toi asynkronisen ohjelmoinnin *async*/*await*-rakenteet. C# 6.0 (2015) esitteli useita käytännön parannuksia, kuten merkkijonointerpolaation, staattiset using-lausekkeet, lausekemuotoiset jäsenet, null-ehtoisen operaattorin parannukset sekä suodatellun poikkeuskäsittelyn.

Vuonna 2014 Microsoft avasi C#:n kääntäjäalustan Roslyn lähdekoodin ja siirsi kehityksen GitHubiin .NET Foundation -säätiön alaisuuteen. Samalla käynnistettiin avoimen lähdekoodin .NET Core -alusta, jonka ensimmäinen versio julkaistiin vuonna 2016. Se mahdollisti C#-sovellusten ajamisen Windowsin ohella myös Linux- ja macOS-käyttöjärjestelmissä. Avoimuus laajensi merkittävästi kehittäjäyhteisön osallistumista kielen ja alustan kehitykseen.

C# 7.0 -sarja (2017–2019) sidottiin tiiviisti .NET Core -julkaisusykliin. Versiot toivat muun muassa arvotuuplit, parannetun mallinsovituksen, paikalliset funktiot, ref-palautukset ja suorituskykyä parantavia rakenteita kuten *Span&lt;T&gt;* sekä *ref struct*. C# 8.0 (2019) esitteli nullable-viitetyypit, oletustoteutukset rajapinnoille, asynkroniset virrat sekä indices and ranges -syntaksit. Nämä ominaisuudet vahvistivat kielen asemaa turvallisessa ja monialustaisessa sovelluskehityksessä.

### Yhtenäinen .NET-alusta (5+) ja uusimmat kehitysaskeleet
Vuodesta 2020 alkaen Microsoft yhdisti aiemmat .NET Framework-, .NET Core- ja Xamarin/Mono-haarat yhtenäiseen .NET-alustaan. .NET 5 julkaistiin vuonna 2020, ja sitä seurasivat .NET 6 (2021), .NET 7 (2022), .NET 8 (2023), .NET 9 (2024) ja .NET 10 (2025). Julkaisut noudattavat vuosittaista rytmiä, jossa parilliset .NET-versiot ovat pitkäaikaisen tuen (*Long-Term Support*, LTS) julkaisuja ja parittomat lyhyemmän tuen (*Standard Term Support*, STS) julkaisuja.

C# 9.0 julkaistiin .NET 5:n yhteydessä vuonna 2020. Versio toi record-tyypit, *init only* -ominaisuudet, ylä­tason ohjelmat sekä parannuksia mallinsovitukseen. C# 10.0 (2021) esitteli globaalit *using*-lauselmat, tiedostokohtaiset nimiavaruudet, record struct -tyypit sekä parannuksia lambda-lausekkeisiin.

C# 11.0 (2022) toi raa'at merkkijonoliteraalit, listamallit, geneeriset attribuutit ja *required*-jäsenet. C# 12.0 (2023) laajensi pääkonstruktorit luokkiin ja rakenteisiin, lisäsi kokoelmailmaisut sekä paransi lambda-parametrien oletusarvoja ja geneeristä ohjelmointia.

C# 13.0 (2024) ja C# 14.0 (2025) julkaistiin .NET 9- ja .NET 10 -alustojen mukana. Versiot toivat parannuksia muun muassa params-kokoelmiin, lock-objektiin, ref struct -rajapintoihin sekä tyyppien laajentamiseen ilman perintää (extension members). Kielen kehitys jatkuu vuosittaisena ja avoimena prosessina .NET-alustan rinnalla.

## Suunnittelutavoitteet ja vaikutteet
### Suunnittelutavoitteet
C# suunniteltiin yleiskäyttöiseksi, moderniksi ohjelmointikieleksi, joka tukee useita ohjelmointiparadigmoja mutta säilyttää C-suvun kielille tyypillisen syntaksin. Kielen keskeisiin tavoitteisiin kuuluivat vahva staattinen tyyppijärjestelmä, automaattinen roskienkeruu sekä tuki turvalliselle ja ylläpidettävälle sovelluskehitykselle. C# suunniteltiin tarjoamaan C++-kielen suorituskykyä muistuttava teho yhdistettynä korkean tason kielen kaltaiseen kehitysmukavuuteen.

C# on tiiviisti sidottu Common Language Infrastructure (CLI) ja Common Language Runtime (CLR) -ympäristöihin. Kielen suunnittelutavoitteisiin kuuluu, että C#:llä kirjoitetut ohjelmat käännetään ECMA-334-määrittelyn mukaan yhteiseen välitasokoodiin Common Intermediate Language (CIL), jota voivat jakaa useat eri CLI-yhteensopivat kielet. Tavoitteena on tukea kielien välistä yhteentoimivuutta eri CLI-yhteensopivien kielten, kuten Visual Basic .NETin ja muiden .NET-kielten, välillä, sekä vahvaa tyyppiturvallisuutta, versioitavuutta ja komponenttipohjaista sovelluskehitystä.

Kielen suunnittelussa otettiin huomioon sekä järjestelmäohjelmoinnin että sovelluskehityksen tarpeet. C# tarjoaa korkean tason ominaisuuksia, kuten poikkeuskäsittelyn, automaattisen muistinhallinnan ja laajan luokkakirjaston, mutta mahdollistaa myös matalamman tason ohjelmoinnin esimerkiksi osoittimia hyödyntävän *unsafe*-tilan kautta silloin, kun halutaan minimoida roskienkeruun aiheuttamia viiveitä tai integroitua olemassa oleviin rajapintoihin.

### Vaikutteet muista kielistä
C# kuuluu syntaksiltaan C-sukuisiin kieliin, ja sen perusrakenne – lohkot, ohjausrakenteet, tyyppimääritykset ja operaattorit – muistuttavat läheisesti C++- ja Java-kieliä. Tämä helpottaa siirtymistä aiemmista C-tyyppisistä kielistä C#:ään, ja mahdollistaa olemassa olevien ohjelmointitapojen hyödyntämisen .NET-ympäristössä. C#:n olio-malli, rajapinnat ja poikkeuskäsittely noudattavat pitkälti samoja periaatteita kuin muissa modernissa olio-ohjelmointikielissä.

Kielen suunnitteluun vaikuttivat myös komponenttipohjaiset kielet ja ympäristöt, kuten Visual Basic ja Delphi, joissa korostuvat ominaisuudet, tapahtumat ja versioitavat kirjastot. C#:ssä nämä ideat yhdistyvät CLR:n metatietomalliin ja kokoonpanoihin (*assemblies*), mikä tukee komponenttipohjaista ohjelmistokehitystä, uudelleenkäytettävyyttä ja versiohallittuja kirjastoja.

Lisäksi C#:n kehityksessä on omaksuttu ideoita mm. funktionaalisesta ohjelmoinnista, mikä näkyy esimerkiksi lambda-lausekkeiden, LINQ-kyselyjen ja mallinsovituksen kaltaisina ominaisuuksina. Kielen myöhemmät versiot ovat tuoneet lisää funktionaalisia piirteitä, kuten immuuttisuutta korostavia record-tyyppejä ja ilmaisupuita, säilyttäen samalla taaksepäin yhteensopivuuden alkuperäisen C-tyylisen syntaksin kanssa.

## Tyyppijärjestelmä ja muistinhallinta
### Tyyppijärjestelmä
C#:ssä on staattinen ja vahva tyyppijärjestelmä, joka perustuu CLI:n yhteiseen tyyppijärjestelmään (*Common Type System*, CTS). Kaikki tyypit – sekä kielen sisäänrakennetut että käyttäjän määrittelemät – jakautuvat kahteen pääryhmään: arvotyyppeihin (esimerkiksi peruslukutyypit, rakenteet ja enumeraatiot) ja viitetyyppeihin (esimerkiksi luokat, rajapinnat, taulukot ja delegaatit. Tyyppijärjestelmä on nimellinen ja suunniteltu siten, että kääntäjä ja CLR voivat tarkistaa tyypinmukaisuuden ja estää suuren osan ajoaikaisista tyyppivirheistä jo käännösvaiheessa.

Arvotyypit tallennetaan tyypillisesti suoraan muuttujan muistipaikkaan (esimerkiksi pinossa tai osana toista rakennetta), kun taas viitetyypeistä talletetaan viite kekoon varattuun olioon. Kaikki tyypit voidaan käsitellä *[[Olio (ohjelmointi)|object]]*-perustyypin kautta, mikä mahdollistaa yhtenäisen käsittelyn ja esimerkiksi kokoelmiin tallentamisen. Arvotyypin pakkaaminen (*boxing*) muuntaa sen viitetyypiksi ja purkaminen (*unboxing*) takaisin arvotyypiksi; tämä on osa CTS-määrittelyä ja vaikuttaa sekä suorituskykyyn että muistinkäyttöön.

Kieli tukee laajaa joukkoa generisia kokoelmia ja geneeristä ohjelmointia, jossa tyyppiparametrit välitetään suoraan CLR-tason generisyytenä ilman tyyppien poistoa (*type erasure*). Tämä parantaa suorituskykyä ja vähentää pakkausoperaatioiden tarvetta verrattuna ei-geneerisiin rakenteisiin. Lisäksi C#:n tyyppipäättely (esimerkiksi *var*-avainsanan ja lambda-lausekkeiden yhteydessä) helpottaa koodin kirjoittamista muuttamatta tyyppijärjestelmän staattista luonnetta.

C#:n null-käsittely perustuu sekä arvotyyppien nullable-laajennoksiin (*T?* enumeraatioille ja muille arvotyypeille) että nullable-viitetyyppeihin, jotka otettiin käyttöön C# 8.0 -versiossa. Null-viitetyypit yhdistävät käännösaikaisen analyysin ja annotaatiot (esimerkiksi *string?* ja *string*) vähentääkseen null-viitevirheiden todennäköisyyttä tuotantokoodissa.

### Muistinhallinta
C#:ssa muistinhallinta on pääosin automaattista ja perustuu roskienkeruuseen CLR-ympäristössä. CLR hallinnoi viitetyyppien elinkaarta sijoittamalla ne hallittuun kekoon ja keräämällä käyttämättömät oliot pois generaatioperusteisen roskienkeruun avulla. Tämä vähentää muistivuotojen riskiä ja helpottaa sovelluskehitystä verrattuna manuaaliseen muistinhallintaan, mutta tekee olioiden tuhoamisesta ei-determinististä: ohjelmoija ei voi tarkasti kontrolloida, milloin yksittäinen olio vapautetaan.

Resurssien hallintaa varten C# tarjoaa deterministisen käyttömallin IDisposable-rajapinnan ja *using*-rakenteen kautta. Mallin ideana on, että hallitun olion taustalla oleva järjestelmäresurssi (esimerkiksi tiedostokahva, verkkoyhteys tai tietokantayhteys) vapautetaan viipymättä, vaikka itse olio jäisi roskienkeruun varaan. Tarvittaessa luokka voi määritellä myös finalisaattorin (*finalizer*), jonka CLR suorittaa ennen olion lopullista poistamista, mutta tätä pidetään yleensä viimeisenä varotoimena eikä ensisijaisena resurssinhallintamekanismina.

Vaikka C# on suunniteltu korkeantason ja turvalliseksi kieleksi, se tarjoaa myös mahdollisuuden hallitumpaan järjestelmäohjelmointiin ”unsafe”-tilan avulla. *unsafe*-koodissa voidaan käyttää osoittimia ja esimerkiksi *stackalloc*-operaattoria pinokohtaiseen muistiallokointiin, mikä antaa kokeneille kehittäjille mahdollisuuden optimoida suorituskykykriittisiä osia tai integroida olemassa oleviin natiiveihin rajapintoihin. Uudemmat ominaisuudet, kuten *Span<T>* ja ref struct -tyypit, laajentavat tätä kykyä tarjoamalla muistiturvallisempia tapoja käsitellä viipaleita hallitusta tai hallitsemattomasta muistista ilman ylimääräisiä kopioita.

## Oliopohjaisuus ja perintä
### Oliopohjaisuus
C# tukee täysimääräisesti olio-ohjelmoinnin perusperiaatteita: abstraktiota, kapselointia, perintää ja polymorfismia. Kielen oliomalli rakentuu luokkien (*class*) ja rakenteiden (*struct*) ympärille. Kaikki C#:n viitetyypit perivät lopulta *[[Olio (ohjelmointi)|object]]*-perustyypistä, mikä tarjoaa yhtenäisen joukon perittyjä jäseniä (esimerkiksi *ToString()*, *Equals()* ja *GetHashCode()*) kaikille olioille. Oliot kapseloivat tilansa ja toimintonsa muokkausrajoitteiden ja pääsynvalvontamääreiden (*public*, *internal*, *protected*, *private*) avulla.

### Perintä
Perintä C#:ssä perustuu yksinkertaiseen luokkaperintään: jokaisella luokalla voi olla vain yksi suora kantaluokka (*base class*). C#-kieli ei aseta rajoituksia perintähierarkian syvyydelle.Johdettu luokka määritellään kaksoispiste-syntaksilla (*class Derived : Base*), ja se voi käyttää kantaluokan jäseniä sekä laajentaa tai muokata niiden toiminnallisuutta. Rakenteet (*struct*) ovat arvotyyppejä, eivätkä ne voi periä toisista rakenteista tai luokista, mutta ne voivat toteuttaa rajapintoja.

Polymorfismi toteutetaan C#:ssä virtuaalisten jäsenten ja ylikirjoituksen avulla. Kantaluokan jäsen voidaan merkitä virtuaaliseksi avainsanalla *virtual* tai abstraktiksi avainsanalla *abstract*, jolloin johdetut luokat voivat määritellä oman toteutuksensa avainsanalla *override*. Näin olion todellinen tyyppi ratkaisee ajoaikaisesti, mitä metodia kutsutaan, vaikka viitteen tyyppi olisi kantaluokka. Luokka tai jäsen voidaan puolestaan merkitä avainsanalla *sealed* estämään jatkoperintä ja ylikirjoittaminen, jolloin tyyppi tai jäsen lukitaan nykyiseen muotoonsa.

Usean kantaluokan perinnän sijaan C#:ssä käytetään rajapintoja (*interface*) tyypillisesti ”sopimusten” kuvaamiseen. Luokka tai rakenne voi toteuttaa useita rajapintoja samanaikaisesti (*class Sample : IFoo, IBar*), jolloin se sitoutuu tarjoamaan rajapintojen määrittelemät jäsenet. Rajapinnat tukevat myös polymorfismia, sillä rajapinnan kautta käsitelty olio voidaan korvata millä tahansa toteutustyypillä, joka toteuttaa kyseisen rajapinnan. C# 8.0 toi rajapinnoille mahdollisuuden määritellä oletustoteutuksia (*default interface methods*), joiden avulla rajapintaan voidaan lisätä uusia jäseniä rikkomatta aiempia toteutuksia; toteuttava tyyppi voi halutessaan ylikirjoittaa oletuskäyttäytymisen.

C# 9.0 -versiosta alkaen kieleen lisättiin record-tyypit, jotka tarjoavat oliopohjaisen mutta arvosemanttisen mallin erityisesti tietomalleja varten. *record class* on viitetyyppi, joka tukee perintää muiden record-tyyppien kanssa ja määrittelee oletuksena arvoon perustuvan vertailun, kun taas *record struct* on arvotyyppi vastaavalla syntaksilla. Record-tyypit täydentävät perinteistä luokkaperintää tarjoamalla välineen immuuttien ja arvovertailua käyttävien olioiden määrittelyyn samalla, kun ne integroituvat C#:n olemassa olevaan perintä- ja polymorfismimalliin.

## Delegaatit, tapahtumat ja lambda-lausekkeet
### Delegaatit
C#:n delegaatit ovat tyyppejä, jotka edustavat viitteitä metodeihin, joilla on tietty parametri­lista ja paluuarvon tyyppi. Delegaatin ilmentymä kapseloi yhden tai useamman kutsuttavan yksikön (*invocation list*), ja sitä voidaan kutsua aivan kuin tavallista metodia. Delegaatit perustuvat System.Delegate-pohjaluokkaan, ja niiden avulla metodeja voidaan välittää argumentteina, tallettaa muuttujiksi tai rakentaa irrotettuja suunnittelumalleja kuten havaitsijamalli. Delegaatteja on sekä ei-geneerisiä että geneerisiä versioita (esimerkiksi *Action*- ja *Func*-delegaatit). Geneeriset delegaatit tukevat kovarianssia ja kontravarianssia yhteensopivien allekirjoitusten välillä.

Useimmat C#:ssa käytettävät delegaatit ovat monilähetysdelegaatteja (*multicast delegates*), joiden kutsulista voi sisältää useita metodeja. Kun delegaattia kutsutaan, sen kutsulistan kaikki jäsenet suoritetaan järjestyksessä. Tätä hyödynnetään esimerkiksi tapahtumankäsittelyssä, jossa samaan tapahtumaan voidaan liittää useita käsittelijöitä (*event handlers*).

### Tapahtumat
Tapahtumat (*events*) rakentuvat delegaattien varaan ja tarjoavat vakiintuneen mallin, jossa yksi luokka (*julkaisija*) voi ilmoittaa kiinnostavista tilanmuutoksista muille luokille (*tilaajat*). Tapahtuma määritellään *event*-avainsanalla ja liitetään tiettyyn delegaattityyppiin; tilaajat rekisteröivät käsittelijänsä käyttämällä *+=*-operaattoria ja poistavat ne *−=*-operaattorilla. Vain tapahtuman määritellyt luokka voi ”laukaista” (*raise*) tapahtuman, mikä auttaa rajaamaan sen elinkaarta ja ylläpitämään kapselointia. Yleinen käytäntö on hyödyntää EventHandler- ja *EventHandler&lt;TEventArgs&gt;*-delegaatteja sekä EventArgs-pohjaisia tietoluokkia, jolloin tapahtumien allekirjoitukset pysyvät yhdenmukaisina .NET-ekosysteemissä.

### Lambda-lausekkeet
Lambda-lausekkeet tarjoavat tiiviin syntaksin anonyymien funktioiden määrittelyyn ja ovat keskeinen osa C#:n funktionaalisia piirteitä. Lambda-lauseke määritellään *=&gt;*-operaattorin avulla, joka erottaa parametrit ja lausekkeen tai koodilohkon (esimerkiksi *x =&gt; x * x*). Lambda voi olla joko lausekelambda (*expression lambda*) tai lausekelohkoa käyttävä lauselambda (*statement lambda*). Lambda-lausekkeet voidaan muuntaa sekä delegaatti-ilmentymiksi että ilmaisupuiksi, mitä hyödynnetään muun muassa LINQ-tekniikoissa ja dynaamisissa kyselykirjastoissa.

Kielen tasolla lambda-lausekkeet ovat syntaktinen lyhennys anonyymeille delegaateille, ja niitä voi käyttää kaikissa yhteyksissä, joissa odotetaan delegaattityyppiä tai sopivaa geneeristä funktiotyyppiä. Lambda-lausekkeet voivat muodostaa sulkeumia (*closures*), jolloin ne säilyttävät viittaukset ympäröivän koodin paikallisiin muuttujiin tai instanssitilaan myöhempiä takaisinkutsuja varten. Myöhemmissä C#:n versioissa lambda-lausekkeita on laajennettu muun muassa luonnollisen tyypin päättelyllä, attribuuttien ja oletusparametrien tuella sekä ilmaisumuotoisilla jäsenillä (*expression-bodied members*), mikä on tehnyt niistä keskeisen osan nykyaikaista C#-ohjelmointia.

## Geneerisyys
C#:n geneerisyys otettiin käyttöön C# 2.0 -versiossa osana .NET Framework 2.0 -alustaa. Geneeristen tyyppien ja menetelmien tavoitteena on parantaa tyyppiturvallisuutta ja suorituskykyä verrattuna ei-geneerisiin kokoelmiin ja yleiskäyttöisiin viitepohjaisiin ratkaisuihin. Geneeriset tyypit ja metodit määritellään tyyppiparametrien (esimerkiksi *List&lt;T&gt;*, *Dictionary&lt;TKey,TValue&gt;* tai *void Swap&lt;T&gt;(ref T x, ref T y)*) avulla, ja niitä voidaan käyttää sekä luokissa, rakenteissa, rajapinnoissa että delegaateissa.

C#:n geneerisyys on toteutettu CLR-tasolla reifioituina geneerisinä tyyppeinä, mikä tarkoittaa, että tyyppiparametrien konkreettinen tyyppi säilyy ajon aikana ilman tyyppien poistoa (*type erasure*). Tämä mahdollistaa sen, että geneeriset kokoelmat, kuten *List&lt;T&gt;*, voivat säilyttää arvotyyppejä ilman pakkausta (*boxing*), mikä vähentää sekä ylimääräistä muistinkäyttöä että ajoaikaista kuormaa verrattuna ei-geneerisiin kokoelmiin (esimerkiksi *System.Collections.ArrayList*). Samalla geneerinen tyyppijärjestelmä mahdollistaa täyden käännöaikaisen tarkistuksen ilman heijastukseen perustuvaa dynamiikkaa.

### Rajoitteet ja tyyppiparametrit
Geneerisiä tyyppiparametreja voidaan rajoittaa rajoitteilla (*constraints*), jotka määritellään *where*-lausekkeiden avulla. Rajoitteiden avulla voidaan esimerkiksi edellyttää, että tyyppiparametri on viitetyyppi (*where T : class*), arvotyyppi (*where T : struct*), tiettyä rajapintaa tai kantaluokkaa toteuttava tyyppi (*where T : IDisposable* tai *where T : BaseClass*) tai tyyppi, jolla on julkinen parametriton konstruktori (*where T : new()*). Myöhemmissä versioissa (alkaen C# 7.3) on lisätty uusia rajoitteita, kuten *unmanaged*-rajoite matalan tason muistirakenteita varten sekä useiden rajoitteiden yhdistäminen samaan tyyppiparametriin. Rajoitteet parantavat geneeristen API-rajapintojen ilmaisukykyä ja helpottavat staattista analyysiä.

### Kovarianssi ja kontravarianssi
Kovarianssi ja kontravarianssi mahdollistaa yhteensopivuuden eritasoisten tyyppihierarkioiden kanssa ilman ylimääräisiä tyyppimuunnoksia. Esimerkiksi *IEnumerable&lt;out T&gt;* on kovariantti tyyppiparametrinsa suhteen, jolloin *IEnumerable&lt;Derived&gt;* voidaan käsitellä *IEnumerable&lt;Base&gt;*-tyyppinä, kun *Derived* perii *Base*-tyypistä. Vastaavasti kontravarianttiset delegaatit ja rajapinnat voivat vastaanottaa laajemman tyyppijoukon argumentteja, mikä helpottaa suunnittelumallien ja irrotettujen API-rajapintojen toteuttamista.

Geneerisyys on laajentunut myöhemmissä C#:n versioissa uusilla ominaisuuksilla, kuten geneerisillä attribuuteilla (*generic attributes*) ja parannetuilla päättelysäännöillä tyyppiparametreille. C# 11.0 toi mahdollisuuden määritellä attribuutteja, joilla on tyyppiparametreja (esimerkiksi *[MyAttribute&lt;T&gt;]*) ja joita voidaan käyttää geneeristen API-rajapintojen ja metatietojen mallintamiseen aiempaa täsmällisemmin. Geneerisyys muodostaa myös perustan monille muille kielen ominaisuuksille, kuten LINQ-kirjastoille, asynkroniselle ohjelmoinnille (*Task&lt;TResult&gt;*) ja lukuisille .NET-ekosysteemin kokoelmille ja apuluokille.

## LINQ
LINQ (*Language Integrated Query*) on C#:n kyselyominaisuus, joka otettiin käyttöön C# 3.0 -versiossa vuonna 2007 osana .NET Framework 3.5 -alustaa. LINQ mahdollistaa yhtenäisen, tyyppiturvallisen ja käännösaikaisesti tarkistetun tavan suorittaa kyselyitä erilaisiin tietolähteisiin suoraan C#-koodissa ilman erillisiä kyselykieliä tai merkkijonojen käsin muodostamista. Ominaisuus rakentuu useiden C# 3.0:n uusien kielielementtien varaan: lambda-lausekkeisiin, laajennusmetodeihin, anonyymeihin tyyppeihin, paikalliseen tyyppipäättelyyn (*var*), ilmaisupuihin sekä osittaisiin metodeihin.

### Syntaksi
LINQ tukee kahta rinnakkaista syntaksia: kyselysyntaksia (*query syntax*), joka muistuttaa SQL:ää, sekä metodisyntaksia (*method syntax*), joka käyttää ketjutettuja laajennusmetodikutsuja. Kyselysyntaksi käännetään kääntäjän toimesta metodisyntaksiksi, joten molemmat ovat semanttisesti identtisiä. Tyypillisiä LINQ-operaattoreita ovat muun muassa *Select*, *Where*, *OrderBy*, *GroupBy*, *Join* ja *Aggregate*. Operaattorit on toteutettu geneerisinä laajennusmetodeina *System.Linq.Enumerable*- ja *System.Linq.Queryable*-luokkiin, jotka toimivat kaikilla tyypeillä, jotka toteuttavat *IEnumerable&lt;T&gt;*- tai *IQueryable&lt;T&gt;*-rajapinnan.

### Ilmaisupuut ja providerit
Keskeinen LINQ:n arkkitehtuurinen piirre on ilmaisupuut (*expression trees*), jotka mahdollistavat kyselyjen esittämisen tietorakenteina suoritettavan koodin sijaan. Kun kysely kohdistuu *IQueryable&lt;T&gt;*-tyyppiin, kääntäjä muodostaa ilmaisupuusta esityksen, joka välitetään providerille; provider voi muuntaa sen esimerkiksi SQL-kyselyksi tietokantaa varten tai muuksi kohdejärjestelmän ymmärtämäksi muodoksi. Tunnettuja LINQ-providereita ovat LINQ to Objects (paikallisille kokoelmille), LINQ to XML, LINQ to DataSet, LINQ to SQL sekä Entity Frameworkin tarjoama LINQ to Entities. Myöhemmin kehitetyt rinnakkais- ja asynkroniset laajennukset, kuten PLINQ ja asynkroniset kyselyt (C# 8.0+), laajentavat LINQ:n käyttöä suorituskykykriittisiin ja I/O-painotteisiin skenaarioihin.

LINQ on muodostunut yhdeksi C#:n eniten käytetyistä ominaisuuksista, ja sillä on keskeinen rooli nykyaikaisessa .NET-kehityksessä tietojen käsittelyssä, suodatuksessa ja muuntelussa. Se on vaikuttanut myös monien kolmannen osapuolen kirjastojen suunnitteluun ja toimii perustana esimerkiksi Reactive Extensions (Rx) -kirjastolle sekä useille data-analytiikka- ja raportointityökaluille.

## Asynkroninen ohjelmointi (async/await)
C#:n tuki asynkroniselle ohjelmoinnille perustuu *async*- ja *await*-avainsanoihin, jotka otettiin käyttöön C# 5.0 -versiossa vuonna 2012 osana .NET Framework 4.5 -alustaa. Ominaisuus mahdollistaa ei-blokkaavan koodin kirjoittamisen synkronisen kaltaisella rakenteella, mikä helpottaa erityisesti I/O-painotteisten operaatioiden, kuten tiedostojen lukemisen, verkkopyyntöjen ja tietokantakyselyiden käsittelyä ilman erillisiä säikeitä tai takaisinkutsuja.

### Perusteet

Metodi merkitään *async*-avainsanalla, jolloin se voi sisältää yhden tai useamman *await*-operaattorin. *Await* keskeyttää metodin suorituksen odottaessaan asynkronisen operaation valmistumista, mutta vapauttaa kutsuvan säikeen muihin tehtäviin. 

Käytännössä malli rakentuu .NET:in säiepoolin ja käyttöjärjestelmän tarjoamien asynkronisten I/O-mekanismien varaan: säikeet toimivat edelleen suoritusyksikköinä, mutta niiden hallinta on kapseloitu *Task*- ja *async/await*-abstraktioiden taakse, mikä vähentää kehittäjän tarvetta käsitellä säikeitä suoraan. 

Vaikka perinteinen *System.Threading.Thread*-luokka on yhä käytettävissä yksittäisten säikeiden luomiseen ja ohjaamiseen, nykyaikaisessa C#-koodissa suositaan yleensä *Task*- ja *async/await*-pohjaisia malleja säikeiden hallinnan yksinkertaistamiseksi. Paluutyyppinä käytetään tyypillisesti *Task* tai *Task&lt;T&gt;*, jotka edustavat asynkronista operaatiota ja sen mahdollista tulosta; erityistapauksena voidaan käyttää myös *ValueTask*-pohjaisia tyyppejä suorituskykykriittisissä skenaarioissa. Kääntäjä muuntaa *async*-metodin tilakoneeksi (*state machine*), joka hallitsee jatkamisia sekä poikkeusten käsittelyä ja suoritus­kontekstin säilyttämistä.

*Async*/*await*-malli integroituu saumattomasti .NET-ekosysteemiin ja on muodostunut vakiintuneeksi tavaksi käsitellä asynkronisuutta esimerkiksi ASP.NET-verkkosovelluksissa, .NET MAUI -mobiilisovelluksissa ja pilvipalveluissa. Se vähentää säikeiden hallinnan monimutkaisuutta ja parantaa sovellusten skaalautuvuutta verrattuna perinteisiin säiemalleihin tai tapahtumapohjaiseen asynkronisuuteen.

### Asynkroniset virrat
C# 8.0 -versiossa käyttöön tulleet asynkroniset virrat (*async streams*) laajentavat mallia tukemaan *IAsyncEnumerable&lt;T&gt;*-rajapintaa. Tämä mahdollistaa tietojen tuottamisen ja kuluttamisen asynkronisesti *await foreach* -rakenteella, mikä soveltuu erityisesti reaaliaikaiseen datan käsittelyyn ja suurten tietomäärien striimaukseen ilman koko tuloksen lataamista muistiin kerralla. Asynkroniset virrat täydentävät perinteistä *Task*-pohjaista mallia tarjoamalla luonnollisen tavan mallintaa sekvenssejä, joissa sekä yksittäisten alkioiden tuotto että koko sekvenssi ovat asynkronisia.

## Mallinsovitus (pattern matching)
C#:n mallinsovitus (*pattern matching*) on kielirakenne, joka mahdollistaa arvojen ja olioiden rakenteen tarkistamisen sekä tietojen purkamisen ehdollisessa ja tiiviissä muodossa. Ominaisuus otettiin käyttöön C# 7.0 -versiossa vuonna 2017 ja sitä on laajennettu merkittävästi myöhemmissä versioissa. Mallinsovitus korvaa ja laajentaa perinteisiä *if*- ja *switch*-lauseita tarjoamalla ilmaisuvoimaisemman tavan käsitellä monimuotoisia tietorakenteita, kuten olioiden tyyppejä, ominaisuuksia ja arvoja.

### Syntaksi
Mallinsovitusta käytetään ensisijaisesti *is*-lausekkeen ja *switch*-lauseen yhteydessä. *is*-lauseke tarkistaa, vastaako muuttuja tiettyä mallia, ja voi samalla purkaa arvon uuteen muuttujaan (esimerkiksi *if (obj is string s)*). *switch*-lause tukee mallipohjaista haarautumista, jossa kukin *case* määrittelee mallin ja valinnaisen ehdon (*when*-lauseke). C# 8.0 toi *switch*-ilmaisun (*switch expression*), joka palauttaa arvon ja käyttää tiiviimpää nuolisyntaksia. Myöhemmät versiot ovat lisänneet relaatiomalleja (*>*, *<* jne.), loogisia malleja (*and*, *or*, *not*), sulkeita ryhmittelyyn sekä listamalleja (C# 11.0).

### Kehitys versioittain
C# 7.0 toi ensimmäiset mallinsovitusominaisuudet tyyppi- ja vakio­malleilla *is*-lausekkeessa ja *switch*-lauseessa. C# 8.0 laajensi mallinsovitusta ominaisuusmalleilla (*property patterns*) ja *switch*-ilmaisulla, jotka helpottavat olioiden purkamista ominaisuuksiensa perusteella. C# 9.0 -versiosta alkaen mallinsovitus tukee relaatiomalleja ja loogisia yhdistelmiä suoraan *is*-lausekkeessa sekä yksinkertaistettua tyyppitarkistusta (esimerkiksi *obj is not null*). C# 10.0 paransi ominaisuusmalleja ja C# 11.0 lisäsi listamallit sekä viipalemallit (*slice patterns*, ..-operaattori), jotka soveltuvat erityisesti kokoelmien ja taulukoiden käsittelyyn.

Mallinsovitus on muodostunut keskeiseksi osaksi modernia C#-ohjelmointia erityisesti tietomallien, syötteen validoinnin ja monimuotoisten tietorakenteiden käsittelyn yhteydessä. Se parantaa koodin luettavuutta ja turvallisuutta vähentäen manuaalisten tyyppitarkistusten, tyyppimuunnosten ja poikkeuskäsittelyn tarvetta.

## Muut keskeiset ominaisuudet
### Nullable-viitetyypit
C# 8.0 -versiossa käyttöön otetut nullable-viitetyypit laajentavat tyyppijärjestelmää erottelemalla viitetyypit, jotka voivat olla null-arvoisia (esimerkiksi *string?*) ja jotka eivät voi (*string*). Kääntäjä suorittaa virta-analyysin (*flow analysis*) ja varoittaa mahdollisista null-viitepoikkeuksista jo käännösaikana. Ominaisuus on valinnainen ja otetaan käyttöön projektitasolla *<Nullable>enable</Nullable>*-asetuksella tai *#nullable enable*-direktiivillä. Nullable-viitetyypit parantavat tuotantokoodin turvallisuutta ja ovat muodostuneet suosituksi käytännöksi uusissa .NET-projekteissa.

### Record-tyypit
C# 9.0 toi record-tyypit, jotka tarjoavat tiiviin syntaksin tietojen kantamiseen tarkoitettujen tyyppien määrittelyyn. *record class* on viitetyyppi ja *record struct* arvotyyppi; molemmat tukevat oletuksena arvoon perustuvaa vertailua (*value-based equality*), *with*-ilmaisuja immuuttien kopioiden luomiseen sekä dekonstruktiota. Recordien pääkonstruktori (*primary constructor*) mahdollistaa ominaisuuksien määrittelyn suoraan tyypin otsikossa (esimerkiksi *public record Person(string FirstName, string LastName);*). Recordit täydentävät perinteisiä luokkia erityisesti tietomallien ja DTO-objektien (*data transfer object*) yhteydessä.

### Ylätason lauseet ja tiedostokohtaiset nimiavaruudet
C# 9.0 esitteli ylätason lauseet (*top-level statements*), joiden avulla ohjelman päälogiikka voidaan kirjoittaa suoraan tiedoston alkuun ilman eksplisiittistä *Main*-metodia tai luokkarakennetta. C# 10.0 toi tiedostokohtaiset nimiavaruudet (*file-scoped namespaces*), jotka määritellään yhden rivin syntaksilla ja kattavat koko tiedoston. Nämä ominaisuudet yksinkertaistavat erityisesti pienten ohjelmien ja skriptien kirjoittamista sekä parantavat koodin luettavuutta suuremmissa projekteissa.

### Pääkonstruktorit luokissa ja rakenteissa sekä kokoelmailmaisut
C# 12.0 laajensi pääkonstruktorit (*primary constructors*) koskemaan myös luokkia ja rakenteita aiemman record-rajoituksen sijaan. Samalla käyttöön tulivat kokoelmailmaisut (*collection expressions*), jotka mahdollistavat kokoelmien alustamisen tiiviillä syntaksilla (esimerkiksi *int[] array = [1, 2, 3];*). Ominaisuudet vähentävät toistoa ja parantavat koodin luettavuutta erityisesti tietorakenteiden alustuksessa.

### Uusimmat kehitysaskeleet (C# 13–14)
C# 13.0 ja C# 14.0 toivat muun muassa parannuksia *params*-kokoelmiin, *lock*-objektiin, *ref struct* -rajapintoihin sekä *extension members* -ominaisuuden, joka mahdollistaa tyyppien laajentamisen ilman perintää. Kehitys jatkuu vuosittaisena syklinä painottaen suorituskykyä, turvallisuutta ja kehittäjäkokemusta.

## Esimerkkiohjelmat
### Hello, World!
C#-ohjelma tulostaa tekstin *Hello, World!* konsoliin. C# 9.0 -versiosta alkaen ohjelman voi kirjoittaa ylätason lauseilla (*top-level statements*) ilman erillistä *Main*-metodia:


```csharp
using System;

Console.WriteLine("Hello, World!");
```


Sama ohjelma voidaan kirjoittaa myös perinteisellä *Main*-metodilla:


```csharp
using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Hello, World!");
    }
}
```

### Perusluokka ja olio
Esimerkkiluokka, jolla on ominaisuuksia, konstruktori ja metodi, sekä olion luonti:


```csharp
public class Person
{
    public string FirstName { get; }
    public string LastName  { get; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName  = lastName;
    }

    public string GetFullName() => $"{FirstName} {LastName}";
}

// Käyttöesimerkki:
var person = new Person("Grace", "Hopper");
var name   = person.GetFullName(); // "Grace Hopper"
```


### LINQ-kysely
Esimerkissä LINQ-kysely suodattaa taulukosta parilliset luvut ja lajittelee ne laskevaan järjestykseen.


```csharp
using System;
using System.Linq;

int[] numbers = { 1, 2, 3, 4, 5, 6 };

var evens =
    from n in numbers
    where n % 2 == 0
    orderby n descending
    select n;

foreach (int n in evens)
{
    Console.WriteLine(n);
}
// Tuloste: 6, 4, 2
```


### Unsafe-koodi
C#:ssa voidaan kirjoittaa myös *unsafe*-koodia, jolloin osoittimia ja natiivimuistia voidaan käsitellä CLR:n automaattisen muistinhallinnan ulkopuolella. Tällainen koodi merkitään *unsafe*-avainsanalla, ja sitä käytetään tyypillisesti suorituskyvyn optimointiin tai ulkoisten natiivikirjastojen kutsumiseen esimerkiksi P/Invoke-mekanismin avulla.

Esimerkki natiivimuistin allokoinnista ja osoittimen käytöstä unsafe-kontekstissa:
```csharp
unsafe
{
    int arvo = 10;
    int* p = &arvo;   // p osoittaa muuttujaan arvo-muuttujaan
    *p += 5;          // kasvattaa arvoa osoittimen kautta
}
// arvo on nyt 15
```


## Käyttökohteet ja ekosysteemi
C#:ää käytetään laajasti erilaisissa sovelluskehityksen alueilla osana .NET-ekosysteemiä. Kieltä tuetaan sekä Microsoftin omissa että avoimen lähdekoodin toteutuksissa, ja se soveltuu monialustaiseen kehitykseen Windows-, Linux- ja macOS-ympäristöissä.

### Työpöytä- ja mobiilisovellukset
C#:llä kehitetään työpöytä- ja mobiilisovelluksia muun muassa Windows Forms-, WPF- ja .NET MAUI -kehyksillä. .NET MAUI mahdollistaa yhden koodikannan käytön useilla alustoilla, mukaan lukien Windows, macOS, iOS ja Android. Perinteisemmät Windows-työpöytäsovellukset hyödyntävät usein WinUI 3 -käyttöliittymäkirjastoa, kun taas Avalonia-kirjasto mahdollistaa XAML-pohjaisten sovellusten ajamisen useilla alustoilla.

### Verkkosovellukset ja pilvipalvelut
Verkkosovelluksia ja -palveluita rakennetaan tyypillisesti ASP.NET Core -alustalla, joka tukee REST-rajapintoja, MVC-arkkitehtuuria sekä minimalistisia Web API -projekteja. Pilvipalveluissa C# on keskeisessä roolissa Microsoft Azure -ympäristössä, jossa sitä käytetään esimerkiksi Azure Functions -serverless-ratkaisuissa, Azure App Service -sovelluksissa ja konttipohjaisissa mikropalveluissa.

### Pelikehitys
C#-kieltä käytetään pelikehityksessä erityisesti Unity-pelimoottorissa, jota hyödynnetään sekä 2D- että 3D-peleissä useilla alustoilla (PC, konsolit, mobiili, VR). Unityn C#-skriptaus on laajasti käytetty malli kaupallisissa ja indie-peliprojekteissa. Muita C#-tukea tarjoavia pelimoottoreita ovat esimerkiksi Godot ja Stride.

### Blazor ja WebAssembly
Blazor mahdollistaa interaktiivisten verkkosovellusten kehittämisen kokonaan C#:llä selaimessa WebAssembly-tekniikan avulla (Blazor WebAssembly) tai palvelinpohjaisesti (Blazor Server). Molemmat mallit jakavat saman koodikannan ja komponenttipohjaisen rakenteen, mikä vähentää tarvetta JavaScript-koodille.

### Kehitystyökalut ja kirjastot
C#-kehitystä tuetaan useilla työkaluilla, kuten Microsoft Visual Studiolla, Visual Studio Codella ja JetBrains Riderillä. Virallinen .NET SDK sisältää kääntäjät ja suoritusaikaiset komponentit. Kirjastoja ja komponentteja jaellaan NuGet-paketinhallinnan kautta, joka kattaa laajan valikoiman avoimen lähdekoodin kirjastoja (esimerkiksi Entity Framework Core, Serilog, AutoMapper). C#:lle on tarjolla myös koneoppimis- ja data-analytiikkakirjastoja, kuten ML.NET, jota käytetään .NET-pohjaisissa tekoäly- ja data-analytiikkasovelluksissa.

## Standardointi ja toteutukset
C#-kielen määrittely ja toteutukset ovat kehittyneet samanaikaisesti Microsoftin johtaman kehityksen ja avoimen standardoinnin myötä. Kielen ydinspecifikaatio on julkaistu avoimesti, ja toteutuksia on useita sekä suljetun että avoimen lähdekoodin lisensseillä.

### Ecma- ja ISO-standardit
Microsoft toimitti C#-kielen ja siihen liittyvän CLI-määrityksen standardoitavaksi Ecma Internationalille vuonna 2000. Kielestä tuli Ecma-standardi ECMA-334 joulukuussa 2001 (1. painos), ja standardia on päivitetty useaan otteeseen; uusin 7. painos julkaistiin joulukuussa 2023. Standardi kattaa kielen syntaksin ja semantiikan, mutta ei sido toteutusta tiettyyn kirjastoon tai alustaan.

ECMA-334 hyväksyttiin myös kansainväliseksi standardiksi ISO/IEC 23270:2003 (1. painos) ja myöhemmin ISO/IEC 23270:2018 (3. painos). Standardointi on mahdollistanut vaihtoehtoisten toteutusten kehittämisen ja varmistanut kielen yhteensopivuuden eri alustoilla.

Nykyiset C#-versiot (6.0–14.0) ylittävät virallisen ECMA/ISO-standardin kattavuuden, mutta Microsoft julkaisee täydet kielispesifikaatiot avoimesti GitHubissa osana avoimen kehityksen prosessia.

### Microsoft .NET
Virallinen ja laajimmin käytetty toteutus on Microsoftin kehittämä .NET (aiemmin .NET Framework, .NET Core ja Xamarin/Mono). Yhtenäinen .NET-alusta (alkaen .NET 5 vuodesta 2020) sisältää Roslyn-kääntäjän, CLR-suoritusaikaisen ympäristön ja laajan luokkakirjaston. Toteutus tukee Windowsia, Linuxia ja macOS:ää sekä sulautettuja ja mobiilialustoja.

### Avoimen lähdekoodin toteutukset (Mono, Roslyn)
Roslyn (.NET Compiler Platform) on Microsoftin vuodesta 2014 avoimeksi tekemä C#- ja Visual Basic -kääntäjäalusta, joka on lisensoitu MIT-lisenssillä ja kehitetään GitHubissa .NET Foundationin alaisuudessa.

Mono-projekti oli pitkään merkittävin täysin avoimen lähdekoodin .NET-toteutus. Vuodesta 2016 se on ollut osa Microsoftin Xamarin/Mono-projektia, ja sen komponentteja on integroitu yhtenäiseen .NET-alustaan. Mono on edelleen käytössä erityisesti Unity-pelimoottorissa.

### Versiohistoria

Taulukon tiedot.

## Katso myös
* .NET
* C++
* F sharp
* Java
* Rust

## Lähteet

## Aiheesta muualla
* C# – virallinen dokumentaatio (Microsoft)
* ECMA-334 C# Language Specification (Ecma International)
*  C#-kielen kehitysrepositorio ja kielispesifikaatio (GitHub)
* Roslyn-kääntäjäalusta (GitHub)