| C sharp |
|---|
 |
| Paradigma | moniparadigmainen:olio-ohjelmointia,imperatiivinen,funktionaalinen,geneerinen, komponenttipohjainen, tapahtumapohjainen |
| Tyypitys | staattinen, vahva, turvallinen, nimellinen, osittain päätelty |
| Yleinen suoritusmalli | käännettävä (CIL),JIT /AOT |
| Muistinhallinta | automaattinenroskienkeruu (unsafe-tilassa osoittimet) |
| Julkaistu | 2000 |
| Kehittäjä | Microsoft (pääsuunnittelijaAnders Hejlsberg) |
| Vakaa versio | C# 14.0[1] (marraskuu 2025 .NET 10) |
| Merkittävimmät toteutukset | .NET (Microsoft),Mono,Roslyn,Unity |
| Vaikutteet | C++,Java,Delphi,Eiffel |
| Vaikuttanut | Rust,Kotlin,Swift,TypeScript |
| Käyttöjärjestelmä | monialustainen |
| Verkkosivu | https://learn.microsoft.com/dotnet/csharp/ |
| Infobox OK |
- Teknisten rajoitusten vuoksi artikkelin yllä näkyvä otsikko on virheellisessä muodossa. Oikea kirjoitustapa on:C#.
C# (lausutaan ”si sharp”) onMicrosoftin kehittämä yleiskäyttöinen, korkean tasonohjelmointikieli, joka tukee useitaohjelmointiparadigmoja, kuten oliopohjaista,imperatiivista,funktionaalista,geneeristä ja komponenttipohjaista ohjelmointia.[2][3] Kieli on olennainen osa.NET-ekosysteemiä ja sitä käytetään laajasti sekä Microsoftin omissa ettäavoimen lähdekoodin toteutuksissa, kuten.NET-,Mono- jaUnity-ympäristöissä.[2]
Kielessä on staattinen ja vahva tyypitys, automaattinen muistinhallintaroskienkeruun 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.[3] Kieli on suunniteltu moderniksi ja turvalliseksi vaihtoehdoksiC-suvun kielille, säilyttäen samalla moniaC++- jaJava-kielistä tuttuja syntaksisia elementtejä.[4]
C#:llä kehitetään muun muassa yrityssovelluksia,verkkosovelluksia ja -palveluita,pilvipohjaisia ratkaisuja (Microsoft Azure), työpöytä- jamobiilisovelluksia (.NET MAUI), pelejä (Unity), selainpohjaisia sovelluksia (Blazor) sekä data- jatekoälysovelluksia (ML.NET).[2] Uusin vakaa versio on C# 14.0, joka julkaistiin marraskuussa 2025 osana.NET 10 -alustaa.[1]
1990-luvun lopussa Microsoft aloitti.NET-hankkeen yhtenäisen sovelluskehitysalustan luomiseksi. Hankkeen puitteissa aloitettiin uuden C#-ohjelmointikielen kehitys pääsuunnittelijaAnders Hejlsbergin johdolla.[4] Kieli esiteltiin julkisesti vuonna 2000 osana.NET Framework -alustaa jaVisual Studio .NET -kehitysympäristöä.[2]
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öhemminISO/IEC-standardi ISO/IEC 23270.[3] Standardointi helpotti vaihtoehtoisten toteutusten, kuten avoimen lähdekoodinMono-projektin, kehittämistä.[2]
Kielen nimi ”C#” viittaa ohjelmointikielten C-sukuun ja musiikinkorotettuun säveleen (C♯). Virallisissa yhteyksissä nimi kirjoitetaanrisuaitamerkin (#) kanssa ECMA-standardin mukaisesti (”C#”).[4]
Ensimmäinen C#-versio (1.0) julkaistiin vuonna 2002 osana.NET Framework 1.0 -alustaa jaVisual Studio .NET -kehitysympäristöä.[5] Versio tarjosi oliopohjaiset perusrakenteet, kuten luokat, rakenteet, rajapinnat, poikkeuskäsittelyn, ominaisuudet, tapahtumat ja delegaatit, sekä erottelun viite- ja arvotyyppien välillä.[4] Kieli perustui automaattiseenroskienkeruuseenCommon 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.[6] 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 jaLINQ-kyselyjen tukemiseen. Uusia ominaisuuksia olivat lambda-lausekkeet, paikallisen tyypin päättely (var), anonyymit tyypit, laajennusmetodit, kyselylausekerakenne sekä ilmaisupuut (expression trees).[7]
C# 4.0 julkaistiin vuonna 2010.NET Framework 4 -alustan yhteydessä. Versio toi dynaamisen sidonnan (dynamic), nimetyt ja valinnaiset parametrit sekä parannetunkovarianssin ja kontravarianssin geneerisille rajapinnoille ja delegaateille.[8] Ominaisuudet helpottivat yhteentoimivuutta dynaamisten kielten ja COM-komponenttien kanssa.
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 ohjelmoinninasync/await-rakenteet.[9] C# 6.0 (2015) esitteli useita käytännön parannuksia, kuten merkkijonointerpolaation, staattiset using-lausekkeet, lausekemuotoiset jäsenet, null-ehtoisen operaattorin parannukset sekä suodatellunpoikkeuskäsittelyn.[10]
Vuonna 2014 Microsoft avasi C#:n kääntäjäalustanRoslyn lähdekoodin ja siirsi kehityksenGitHubiin.NET Foundation -säätiön alaisuuteen.[11] Samalla käynnistettiin avoimen lähdekoodin .NET Core -alusta, jonka ensimmäinen versio julkaistiin vuonna 2016. Se mahdollisti C#-sovellusten ajamisen Windowsin ohella myösLinux- jamacOS-käyttöjärjestelmissä.[12] 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 kutenSpan<T> sekäref struct.[13][14] C# 8.0 (2019) esitteli nullable-viitetyypit, oletustoteutukset rajapinnoille, asynkroniset virrat sekä indices and ranges -syntaksit.[15] Nämä ominaisuudet vahvistivat kielen asemaa turvallisessa ja monialustaisessa sovelluskehityksessä.
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).[16] 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.[17]
C# 9.0 julkaistiin .NET 5:n yhteydessä vuonna 2020. Versio toi record-tyypit,init only -ominaisuudet, ylätason ohjelmat sekä parannuksia mallinsovitukseen.[18] C# 10.0 (2021) esitteli globaalitusing-lauselmat, tiedostokohtaiset nimiavaruudet, record struct -tyypit sekä parannuksia lambda-lausekkeisiin.[19]
C# 11.0 (2022) toi raa'at merkkijonoliteraalit, listamallit, geneeriset attribuutit jarequired-jäsenet.[20] C# 12.0 (2023) laajensi pääkonstruktorit luokkiin ja rakenteisiin, lisäsi kokoelmailmaisut sekä paransi lambda-parametrien oletusarvoja ja geneeristä ohjelmointia.[21]
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).[22][1] Kielen kehitys jatkuu vuosittaisena ja avoimena prosessina .NET-alustan rinnalla.[23]
C# suunniteltiin yleiskäyttöiseksi, moderniksiohjelmointikieleksi, joka tukee useitaohjelmointiparadigmoja mutta säilyttää C-suvun kielille tyypillisen syntaksin.[4] Kielen keskeisiin tavoitteisiin kuuluivat vahva staattinentyyppijärjestelmä, automaattinenroskienkeruu sekä tuki turvalliselle ja ylläpidettävälle sovelluskehitykselle.[3] C# suunniteltiin tarjoamaanC++-kielen suorituskykyä muistuttava teho yhdistettynä korkean tason kielen kaltaiseen kehitysmukavuuteen.[24]
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älitasokoodiinCommon 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ä.[3][2]
Kielen suunnittelussa otettiin huomioon sekä järjestelmäohjelmoinnin että sovelluskehityksen tarpeet. C# tarjoaa korkean tason ominaisuuksia, kutenpoikkeuskäsittelyn,automaattisen muistinhallinnan ja laajanluokkakirjaston, mutta mahdollistaa myös matalamman tason ohjelmoinnin esimerkiksi osoittimia hyödyntävänunsafe-tilan kautta silloin, kun halutaan minimoida roskienkeruun aiheuttamia viiveitä tai integroitua olemassa oleviin rajapintoihin.[3]
C# kuuluu syntaksiltaanC-sukuisiin kieliin, ja sen perusrakenne – lohkot, ohjausrakenteet, tyyppimääritykset ja operaattorit – muistuttavat läheisestiC++- jaJava-kieliä.[4] 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 modernissaolio-ohjelmointikielissä.
Kielen suunnitteluun vaikuttivat myös komponenttipohjaiset kielet ja ympäristöt, kutenVisual Basic jaDelphi, joissa korostuvat ominaisuudet, tapahtumat ja versioitavat kirjastot.[24] C#:ssä nämä ideat yhdistyvätCLR:n metatietomalliin ja kokoonpanoihin (assemblies), mikä tukee komponenttipohjaista ohjelmistokehitystä, uudelleenkäytettävyyttä javersiohallittuja kirjastoja.
Lisäksi C#:n kehityksessä on omaksuttu ideoita mm.funktionaalisesta ohjelmoinnista, mikä näkyy esimerkiksilambda-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.[25]
C#:ssä on staattinen ja vahvatyyppijä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.[26] 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 viitekekoon varattuun olioon. Kaikki tyypit voidaan käsitellä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 jageneeristä 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 (esimerkiksivar-avainsanan jalambda-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 (esimerkiksistring? jastring) vähentääkseen null-viitevirheiden todennäköisyyttä tuotantokoodissa.[27]
C#:ssa muistinhallinta on pääosin automaattista ja perustuuroskienkeruuseen CLR-ympäristössä. CLR hallinnoi viitetyyppien elinkaarta sijoittamalla ne hallittuun kekoon ja keräämällä käyttämättömät oliot poisgeneraatioperusteisen roskienkeruun avulla.[28] 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 jausing-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.[29] 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 esimerkiksistackalloc-operaattoria pinokohtaiseen muistiallokointiin, mikä antaa kokeneille kehittäjille mahdollisuuden optimoida suorituskykykriittisiä osia tai integroida olemassa oleviin natiiveihin rajapintoihin.Unsafe code, pointers, and function pointers Microsoft. Viitattu 7.12.2025. Uudemmat ominaisuudet, kutenSpan<T> ja ref struct -tyypit, laajentavat tätä kykyä tarjoamalla muistiturvallisempia tapoja käsitellä viipaleita hallitusta tai hallitsemattomasta muistista ilman ylimääräisiä kopioita.[30]
C# tukee täysimääräisestiolio-ohjelmoinnin perusperiaatteita: abstraktiota,kapselointia,perintää japolymorfismia. Kielen oliomalli rakentuu luokkien (class) ja rakenteiden (struct) ympärille. Kaikki C#:n viitetyypit perivät lopultaobject-perustyypistä, mikä tarjoaa yhtenäisen joukon perittyjä jäseniä (esimerkiksiToString(),Equals() jaGetHashCode()) kaikille olioille.[31][32] Oliot kapseloivat tilansa ja toimintonsa muokkausrajoitteiden japääsynvalvontamääreiden (public,internal,protected,private) avulla.
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.[33] Rakenteet (struct) ovat arvotyyppejä, eivätkä ne voi periä toisista rakenteista tai luokista, mutta ne voivat toteuttaa rajapintoja.[32]
Polymorfismi toteutetaan C#:ssä virtuaalisten jäsenten ja ylikirjoituksen avulla. Kantaluokan jäsen voidaan merkitä virtuaaliseksi avainsanallavirtual tai abstraktiksi avainsanallaabstract, jolloin johdetut luokat voivat määritellä oman toteutuksensa avainsanallaoverride. Näin olion todellinen tyyppi ratkaisee ajoaikaisesti, mitä metodia kutsutaan, vaikka viitteen tyyppi olisi kantaluokka.[34] Luokka tai jäsen voidaan puolestaan merkitä avainsanallasealed estämään jatkoperintä ja ylikirjoittaminen, jolloin tyyppi tai jäsen lukitaan nykyiseen muotoonsa.[35]
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öspolymorfismia, 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.[36]
C# 9.0 -versiosta alkaen kieleen lisättiin record-tyypit, jotka tarjoavat oliopohjaisen mutta arvosemanttisen mallin erityisestitietomalleja varten.record class on viitetyyppi, joka tukee perintää muiden record-tyyppien kanssa ja määrittelee oletuksena arvoon perustuvan vertailun, kun taasrecord struct on arvotyyppi vastaavalla syntaksilla.[37] 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.
C#:n delegaatit ovat tyyppejä, jotka edustavat viitteitä metodeihin, joilla on tietty parametrilista 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 irrotettujasuunnittelumalleja kuten havaitsijamalli.[38][39] Delegaatteja on sekä ei-geneerisiä että geneerisiä versioita (esimerkiksiAction- jaFunc-delegaatit). Geneeriset delegaatit tukevatkovarianssia ja kontravarianssia yhteensopivien allekirjoitusten välillä.[40]
Useimmat C#:ssa käytettävät delegaatit ovatmonilä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).[39]
Tapahtumat (events) rakentuvat delegaattien varaan ja tarjoavat vakiintuneen mallin, jossa yksi luokka (julkaisija) voi ilmoittaa kiinnostavista tilanmuutoksista muille luokille (tilaajat). Tapahtuma määritelläänevent-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.[41] Yleinen käytäntö on hyödyntää EventHandler- jaEventHandler<TEventArgs>-delegaatteja sekä EventArgs-pohjaisia tietoluokkia, jolloin tapahtumien allekirjoitukset pysyvät yhdenmukaisina.NET-ekosysteemissä.[42]
Lambda-lausekkeet tarjoavat tiiviin syntaksin anonyymien funktioiden määrittelyyn ja ovat keskeinen osa C#:nfunktionaalisia piirteitä. Lambda-lauseke määritellään=>-operaattorin avulla, joka erottaa parametrit ja lausekkeen tai koodilohkon (esimerkiksix => x * x). Lambda voi olla joko lausekelambda (expression lambda) tai lausekelohkoa käyttävä lauselambda (statement lambda).[43][44] Lambda-lausekkeet voidaan muuntaa sekä delegaatti-ilmentymiksi että ilmaisupuiksi, mitä hyödynnetään muun muassaLINQ-tekniikoissa ja dynaamisissa kyselykirjastoissa.
Kielen tasolla lambda-lausekkeet ovat syntaktinen lyhennys anonyymeille delegaateille, ja niitä voi käyttää kaikissa yhteyksissä, joissa odotetaan delegaattityyppiä tai sopivaageneeristä 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.[43] 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.[45]
C#:ngeneerisyys 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 (esimerkiksiList<T>,Dictionary<TKey,TValue> taivoid Swap<T>(ref T x, ref T y)) avulla, ja niitä voidaan käyttää sekä luokissa, rakenteissa, rajapinnoissa että delegaateissa.[46][47]
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, kutenList<T>, voivat säilyttää arvotyyppejä ilman pakkausta (boxing), mikä vähentää sekä ylimääräistä muistinkäyttöä että ajoaikaista kuormaa verrattuna ei-geneerisiin kokoelmiin (esimerkiksiSystem.Collections.ArrayList).[48] Samalla geneerinen tyyppijärjestelmä mahdollistaa täyden käännöaikaisen tarkistuksen ilman heijastukseen perustuvaa dynamiikkaa.
Geneerisiä tyyppiparametreja voidaan rajoittaa rajoitteilla (constraints), jotka määritelläänwhere-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 taiwhere T : BaseClass) tai tyyppi, jolla on julkinen parametriton konstruktori (where T : new()). Myöhemmissä versioissa (alkaen C# 7.3) on lisätty uusia rajoitteita, kutenunmanaged-rajoite matalan tason muistirakenteita varten sekä useiden rajoitteiden yhdistäminen samaan tyyppiparametriin.[49] Rajoitteet parantavat geneeristen API-rajapintojen ilmaisukykyä ja helpottavatstaattista analyysiä.
Kovarianssi ja kontravarianssi mahdollistaa yhteensopivuuden eritasoisten tyyppihierarkioiden kanssa ilman ylimääräisiä tyyppimuunnoksia. EsimerkiksiIEnumerable<out T> on kovariantti tyyppiparametrinsa suhteen, jolloinIEnumerable<Derived> voidaan käsitelläIEnumerable<Base>-tyyppinä, kunDerived periiBase-tyypistä.[50] Vastaavasti kontravarianttiset delegaatit ja rajapinnat voivat vastaanottaa laajemman tyyppijoukon argumentteja, mikä helpottaasuunnittelumallien 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<T>]) ja joita voidaan käyttää geneeristen API-rajapintojen ja metatietojen mallintamiseen aiempaa täsmällisemmin.[51] Geneerisyys muodostaa myös perustan monille muille kielen ominaisuuksille, kutenLINQ-kirjastoille, asynkroniselle ohjelmoinnille (Task<TResult>) ja lukuisille.NET-ekosysteemin kokoelmille ja apuluokille.
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.[52][53]
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 muassaSelect,Where,OrderBy,GroupBy,Join jaAggregate. Operaattorit on toteutettu geneerisinä laajennusmetodeinaSystem.Linq.Enumerable- jaSystem.Linq.Queryable-luokkiin, jotka toimivat kaikilla tyypeillä, jotka toteuttavatIEnumerable<T>- taiIQueryable<T>-rajapinnan.[54]
Keskeinen LINQ:n arkkitehtuurinen piirre on ilmaisupuut (expression trees), jotka mahdollistavat kyselyjen esittämisen tietorakenteina suoritettavan koodin sijaan. Kun kysely kohdistuuIQueryable<T>-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.[55] 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.[56]
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.[57]
C#:n tuki asynkroniselle ohjelmoinnille perustuuasync- jaawait-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.[58][59]
Metodi merkitäänasync-avainsanalla, jolloin se voi sisältää yhden tai useammanawait-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 kapseloituTask- jaasync/await-abstraktioiden taakse, mikä vähentää kehittäjän tarvetta käsitellä säikeitä suoraan.
Vaikka perinteinenSystem.Threading.Thread-luokka on yhä käytettävissä yksittäisten säikeiden luomiseen ja ohjaamiseen, nykyaikaisessa C#-koodissa suositaan yleensäTask- jaasync/await-pohjaisia malleja säikeiden hallinnan yksinkertaistamiseksi. Paluutyyppinä käytetään tyypillisestiTask taiTask<T>, jotka edustavat asynkronista operaatiota ja sen mahdollista tulosta; erityistapauksena voidaan käyttää myösValueTask-pohjaisia tyyppejä suorituskykykriittisissä skenaarioissa.[60][61] Kääntäjä muuntaaasync-metodin tilakoneeksi (state machine), joka hallitsee jatkamisia sekä poikkeusten käsittelyä ja suorituskontekstin säilyttämistä.
Async/await-malli integroituu saumattomasti.NET-ekosysteemiin ja on muodostunut vakiintuneeksi tavaksi käsitellä asynkronisuutta esimerkiksiASP.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.[62]
C# 8.0 -versiossa käyttöön tulleet asynkroniset virrat (async streams) laajentavat mallia tukemaanIAsyncEnumerable<T>-rajapintaa. Tämä mahdollistaa tietojen tuottamisen ja kuluttamisen asynkronisestiawait foreach -rakenteella, mikä soveltuu erityisesti reaaliaikaiseen datan käsittelyyn ja suurten tietomäärien striimaukseen ilman koko tuloksen lataamista muistiin kerralla.[63] 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.
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.[64] Mallinsovitus korvaa ja laajentaa perinteisiäif- jaswitch-lauseita tarjoamalla ilmaisuvoimaisemman tavan käsitellä monimuotoisia tietorakenteita, kuten olioiden tyyppejä, ominaisuuksia ja arvoja.[65]
Mallinsovitusta käytetään ensisijaisestiis-lausekkeen jaswitch-lauseen yhteydessä.is-lauseke tarkistaa, vastaako muuttuja tiettyä mallia, ja voi samalla purkaa arvon uuteen muuttujaan (esimerkiksiif (obj is string s)).switch-lause tukee mallipohjaista haarautumista, jossa kukincase määrittelee mallin ja valinnaisen ehdon (when-lauseke).[66] C# 8.0 toiswitch-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).[67]
C# 7.0 toi ensimmäiset mallinsovitusominaisuudet tyyppi- ja vakiomalleillais-lausekkeessa jaswitch-lauseessa. C# 8.0 laajensi mallinsovitusta ominaisuusmalleilla (property patterns) jaswitch-ilmaisulla, jotka helpottavat olioiden purkamista ominaisuuksiensa perusteella.[68] C# 9.0 -versiosta alkaen mallinsovitus tukee relaatiomalleja ja loogisia yhdistelmiä suoraanis-lausekkeessa sekä yksinkertaistettua tyyppitarkistusta (esimerkiksiobj 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.[69]
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.[70]
C# 8.0 -versiossa käyttöön otetut nullable-viitetyypit laajentavat tyyppijärjestelmää erottelemalla viitetyypit, jotka voivat olla null-arvoisia (esimerkiksistring?) 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ä.[71][72] Nullable-viitetyypit parantavat tuotantokoodin turvallisuutta ja ovat muodostuneet suosituksi käytännöksi uusissa.NET-projekteissa.
C# 9.0 toi record-tyypit, jotka tarjoavat tiiviin syntaksin tietojen kantamiseen tarkoitettujen tyyppien määrittelyyn.record class on viitetyyppi jarecord 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 (esimerkiksipublic record Person(string FirstName, string LastName);).[73][74] Recordit täydentävät perinteisiä luokkia erityisesti tietomallien ja DTO-objektien (data transfer object) yhteydessä.
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.[75][76] Nämä ominaisuudet yksinkertaistavat erityisesti pienten ohjelmien ja skriptien kirjoittamista sekä parantavat koodin luettavuutta suuremmissa projekteissa.
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 (esimerkiksiint[] array = [1, 2, 3];).[77] Ominaisuudet vähentävät toistoa ja parantavat koodin luettavuutta erityisesti tietorakenteiden alustuksessa.
C# 13.0 ja C# 14.0 toivat muun muassa parannuksiaparams-kokoelmiin,lock-objektiin,ref struct -rajapintoihin sekäextension members -ominaisuuden, joka mahdollistaa tyyppien laajentamisen ilman perintää.[78][79] Kehitys jatkuu vuosittaisena syklinä painottaen suorituskykyä, turvallisuutta ja kehittäjäkokemusta.
C#-ohjelma tulostaa tekstinHello, World! konsoliin. C# 9.0 -versiosta alkaen ohjelman voi kirjoittaa ylätason lauseilla (top-level statements) ilman erillistäMain-metodia:[80]
usingSystem;Console.WriteLine("Hello, World!");Sama ohjelma voidaan kirjoittaa myös perinteiselläMain-metodilla:
usingSystem;classProgram{staticvoidMain(){Console.WriteLine("Hello, World!");}}Esimerkkiluokka, jolla on ominaisuuksia, konstruktori ja metodi, sekä olion luonti:
publicclassPerson{publicstringFirstName{get;}publicstringLastName{get;}publicPerson(stringfirstName,stringlastName){FirstName=firstName;LastName=lastName;}publicstringGetFullName()=>$"{FirstName} {LastName}";}// Käyttöesimerkki:varperson=newPerson("Grace","Hopper");varname=person.GetFullName();// "Grace Hopper"EsimerkissäLINQ-kysely suodattaa taulukosta parilliset luvut ja lajittelee ne laskevaan järjestykseen.
usingSystem;usingSystem.Linq;int[]numbers={1,2,3,4,5,6};varevens=fromninnumberswheren%2==0orderbyndescendingselectn;foreach(intninevens){Console.WriteLine(n);}// Tuloste: 6, 4, 2C#:ssa voidaan kirjoittaa myösunsafe-koodia, jolloinosoittimia ja natiivimuistia voidaan käsitelläCLR:n automaattisen muistinhallinnan ulkopuolella. Tällainen koodi merkitäänunsafe-avainsanalla, ja sitä käytetään tyypillisesti suorituskyvyn optimointiin tai ulkoisten natiivikirjastojen kutsumiseen esimerkiksi P/Invoke-mekanismin avulla.[81]
Esimerkki natiivimuistin allokoinnista ja osoittimen käytöstä unsafe-kontekstissa:
unsafe{intarvo=10;int*p=&arvo;// p osoittaa muuttujaan arvo-muuttujaan*p+=5;// kasvattaa arvoa osoittimen kautta}// arvo on nyt 15C#:ää 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ä.[2]
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.[82] 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.
Verkkosovelluksia ja -palveluita rakennetaan tyypillisestiASP.NET Core -alustalla, joka tukee REST-rajapintoja, MVC-arkkitehtuuria sekä minimalistisia Web API -projekteja. Pilvipalveluissa C# on keskeisessä roolissaMicrosoft Azure -ympäristössä, jossa sitä käytetään esimerkiksi Azure Functions -serverless-ratkaisuissa, Azure App Service -sovelluksissa ja konttipohjaisissa mikropalveluissa.[83][84]
C#-kieltä käytetään pelikehityksessä erityisestiUnity-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.[85] Muita C#-tukea tarjoavia pelimoottoreita ovat esimerkiksi Godot ja Stride.
Blazor mahdollistaa interaktiivisten verkkosovellusten kehittämisen kokonaan C#:llä selaimessaWebAssembly-tekniikan avulla (Blazor WebAssembly) tai palvelinpohjaisesti (Blazor Server). Molemmat mallit jakavat saman koodikannan ja komponenttipohjaisen rakenteen, mikä vähentää tarvettaJavaScript-koodille.[86]
C#-kehitystä tuetaan useilla työkaluilla, kutenMicrosoft Visual Studiolla,Visual Studio Codella ja JetBrains Riderillä. Virallinen.NET SDK sisältää kääntäjät ja suoritusaikaiset komponentit. Kirjastoja ja komponentteja jaellaanNuGet-paketinhallinnan kautta, joka kattaa laajan valikoiman avoimen lähdekoodin kirjastoja (esimerkiksi Entity Framework Core, Serilog, AutoMapper).[87][88] C#:lle on tarjolla myös koneoppimis- ja data-analytiikkakirjastoja, kuten ML.NET, jota käytetään .NET-pohjaisissatekoäly- ja data-analytiikkasovelluksissa.[89]
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ä.
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.[90] Standardi kattaa kielen syntaksin ja semantiikan, mutta ei sido toteutusta tiettyyn kirjastoon tai alustaan.
ECMA-334 hyväksyttiin myös kansainväliseksi standardiksiISO/IEC 23270:2003 (1. painos) ja myöhemmin ISO/IEC 23270:2018 (3. painos).[91] 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.[92]
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.[93]
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äänGitHubissa .NET Foundationin alaisuudessa.[94]
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ä erityisestiUnity-pelimoottorissa.[95]
| C#-versiohistoria |
|---|
| Versio | Julkaisuvuosi | .NET-versio | Merkittäviä ominaisuuksia |
|---|
| C# 1.0 | 2002 | .NET Framework 1.0 | Oliopohjaiset perusrakenteet, delegaatit, ominaisuudet |
| C# 2.0 | 2005 | .NET Framework 2.0 | Geneerisyys, nullable-tyypit, anonyymit metodit |
| C# 3.0 | 2007 | .NET Framework 3.5 | LINQ, lambda-lausekkeet, laajennusmetodit |
| C# 4.0 | 2010 | .NET Framework 4.0 | Dynaaminen tyypitys, nimetyt ja valinnaiset parametrit |
| C# 5.0 | 2012 | .NET Framework 4.5 | Asynkroninen ohjelmointi (async/await) |
| C# 6.0 | 2015 | .NET Framework 4.6 | Merkkijonointerpolointi, null-ehtoinen operaattori |
| C# 7.0–7.3 | 2017–2018 | .NET Core 2.x | Arvotuuplit, mallinsovitus, paikalliset funktiot, ref-palautukset |
| C# 8.0 | 2019 | .NET Core 3.x | Nullable-viitetyypit, oletustoteutukset rajapinnoille, async streams |
| C# 9.0 | 2020 | .NET 5 | Records, top-level statements, init-only-ominaisuudet |
| C# 10.0 | 2021 | .NET 6 | Global using, file-scoped namespaces, record struct -tyypit |
| C# 11.0 | 2022 | .NET 7 | Raw string literals, required-jäsenet, geneeriset attribuutit, listamallit |
| C# 12.0 | 2023 | .NET 8 | Pääkonstruktorit luokille ja rakenteille, collection expressions |
| C# 13.0 | 2024 | .NET 9 | params-kokoelmat, ref struct -rajapinnat, parannuksia lock-rakenteeseen |
| C# 14.0 | 2025 | .NET 10 | Laajennusjäsenet, field-taustaiset ominaisuudet, partial-tapahtumat ja -konstruktorit, null-ehtoinen sijoitus |
Taulukon tiedot.[96]