C Skarp syntax

Den här artikeln beskriver syntaxen för programmeringsspråket C# . Funktionerna som beskrivs är kompatibla med .NET Framework och Mono .

Grunderna

Identifierare

En identifierare är namnet på ett element i koden . Den kan innehålla bokstäver, siffror och understreck ( _ ), och är skiftlägeskänslig ( FOO skiljer sig från foo ). Språket ålägger följande begränsningar för identifierarnamn:

  • De kan inte börja med en siffra;
  • De kan inte börja med en symbol, om det inte är ett nyckelord;
  • De får inte innehålla mer än 511 tecken .

Identifieringsnamn kan föregås av ett atecken ( @ ), men detta är obetydligt; @namn är samma identifierare som namn .

Microsoft har publicerat namnkonventioner för identifierare i C#, som rekommenderar användning av PascalCase för namn på typer och de flesta typmedlemmar, och CamelCase för variabler och för privata eller interna fält. Dessa namnkonventioner tillämpas dock inte i språket.

Nyckelord

Nyckelord är fördefinierade reserverade ord med speciell syntaktisk betydelse. Språket har två typer av nyckelord — kontextuella och reserverade. De reserverade nyckelorden som false eller byte får endast användas som nyckelord. De kontextuella nyckelorden som var eller från behandlas bara som nyckelord i vissa situationer. Om en identifierare behövs som skulle vara samma som ett reserverat nyckelord, kan det föregås av ett atecken för att särskilja det. Till exempel tolkas @out som en identifierare, medan ut som ett nyckelord. Denna syntax underlättar återanvändning av .NET -kod skriven på andra språk.

Följande C# nyckelord är reserverade ord:

  • abstrakt
  • som
  • bas
  • bool
  • ha sönder
  • byte
  • fall
  • fånga
  • röding
  • kontrollerade
  • klass
  • konst
  • Fortsätta
  • decimal
  • standard
  • delegera
  • do
  • dubbel
  • annan
  • uppräkning
  • händelse
  • explicit
  • extern
  • falsk
  • till sist
  • fast
  • flyta
  • för
  • för varje
  • gå till
  • om
  • implicit
  • i
  • int
  • gränssnitt
  • inre
  • är
  • låsa
  • lång
  • namnutrymme
  • ny
  • null
  • objekt
  • operatör
  • ut
  • åsidosätta
  • params
  • privat
  • skyddad
  • offentlig
  • skrivskyddad
  • ref
  • lämna tillbaka
  • sbyte
  • sluten
  • kort
  • storlek av
  • stackalloc
  • statisk
  • sträng
  • struktur
  • växla
  • detta
  • kasta
  • Sann
  • Prova
  • sorts
  • uint
  • lång
  • okontrollerad
  • osäker
  • kort
  • använder sig av
  • virtuell
  • tomhet
  • flyktig
  • medan

Ett kontextuellt nyckelord används för att ge en specifik betydelse i koden, men det är inte ett reserverat ord i C#. Vissa kontextuella nyckelord, som partiell och där , har speciella betydelser i flera sammanhang. Följande C#-nyckelord är kontextuella:

  • Lägg till
  • och
  • alias
  • stigande
  • args
  • asynkron
  • vänta
  • förbi
  • nedåtgående
  • dynamisk
  • lika
  • från
  • skaffa sig
  • global
  • grupp
  • i det
  • in i
  • Ansluta sig
  • låta
  • lyckades
  • namn
  • nint
  • inte
  • inte null
  • nuint
  • eller
  • sortera efter
  • partiell
  • spela in
  • avlägsna
  • nödvändig
  • Välj
  • uppsättning
  • ohanterat
  • värde
  • var
  • när
  • var
  • med
  • avkastning

Bokstäver

Heltal
decimal 23456 , [ 0. . 9 ]+
hexadecimal 0 0 xF5 , x [ 0. . 9 , A..F , a..f ] + _ _ _
binär 0 00 b010110001101 , b [ , 1 ]+
Flyttalsvärden _
flyta 23,5F , 23,5f ; 1,72 E3F , 1,72 E3f , 1,72 e3F , 1,72 e3f
dubbel 23,5 , 23,5D , 23,5d ; 1,72 E3 , 1,72 E3D , ...
decimal 79228162514264337593543950335 m , - 0,00000000000000000000000000001 m , ...
Tecken
röding 'a' , 'Z' , '\ u0231 ' , '\ x30 ' , '\n'
Strängar
sträng

"Hej världen" "C:\\Windows\\" , @"C:\Windows\" [ordrättsliga strängar (föregås av @) kan innehålla radbrytning och vagnreturtecken] $"Hej, {namn}!" Interpolerad sträng. Som en ordagrant sträng: $ @"Hej, {namn}!"
Karaktären rymmer i strängar
Unicode- tecken \ u följt av den hexadecimala unicode-kodpunkten
Extended_ASCII -tecken \ x följt av den hexadecimala utökade ASCII-kodpunkten
Noll karaktär \0
Flik \ t
Backsteg \ b
Vagnretur \ r
Form foder \ f
Omvänt snedstreck \\ _
Enstaka citat \'
Dubbelt citat \ "
Linjematning \ n

Sifferavgränsare

Från och med C# 7.0 kan understreckssymbolen användas för att separera siffror i talvärden för läsbarhetssyften. Kompilatorn ignorerar dessa understreck.

   0
   0
   
    int  bin  =  b1101_0010_1011_0100  ;  int  hex  =  x2F_BB_4A_F1  ;  int  dec  =  1  _000_500_954  ;  dubbel  reell  =  1  _500  .  200  _2e  -  1  _000  ; 

I allmänhet kan det bara sättas mellan siffror. Det kan inte sättas i början ( _121 ) eller slutet av värdet ( 121_ eller 121.05_ ), bredvid decimalen i flyttalsvärden ( 10_.0 ), bredvid exponenttecknet ( 1.1e_1 ) eller bredvid typspecifikationen ( 10_f ).

Variabler

Variabler är identifierare associerade med värden. De deklareras genom att skriva variabelns typ och namn, och initieras valfritt i samma programsats.

Deklarera

           int  myInt  ;  // Deklarera en oinitierad variabel som heter 'myInt', av typen 'int' 

Tilldelar

         
          int  myInt  ;  // Deklarerar en oinitierad variabel  myInt  =  35  ;  // Tilldela variabeln ett värde 

Initiera

       int  myInt  =  35  ;  // Deklarera och initiera variabeln 

Flera variabler av samma typ kan deklareras och initieras i en sats.

           

        int  a  ,  b  ;  // Deklarera flera variabler av samma typ  int  a  =  2  ,  b  =  3  ;  // Deklarera och initiera flera variabler av samma typ 

Lokal variabel typ slutledning

Detta är en funktion i C# 3.0 .

C# 3.0 introducerade typinferens, vilket gör att typspecifikatorn för en variabeldeklaration kan ersättas med nyckelordet var , om dess faktiska typ kan bestämmas statiskt från initialiseraren. Detta minskar upprepning, särskilt för typer med flera generiska typparametrar , och följer DRY -principen närmare .

       

       var  myChars  =  new  char  []  {  'A'  ,  'Ö'  };  // eller char[] myChars = nytt char[] {'A', 'Ö'};  var  myNums  =  new  List  <  int  >();  // eller List<int> myNums = new List<int>(); 

Konstanter

Konstanter är oföränderliga värden.

konst

När du deklarerar en lokal variabel eller ett fält med nyckelordet const som prefix måste värdet anges när det deklareras. Efter det är den låst och kan inte ändras. De kan antingen deklareras i sammanhanget som ett fält eller en lokal variabel. Konstanter är implicit statiska.

     const  dubbel  PI  =  3,14  ; 

Detta visar båda användningarna av nyckelordet.

  

         

     
    
            
    
 offentlig  klass  Foo  {  privat  konst  dubbel  X  =  3  ;  public  Foo  ()  {  const  int  y  =  2  ;  }  } 

skrivskyddad

Det skrivskyddade nyckelordet gör ungefär samma sak som fält. Liksom fält markerade som const kan de inte ändras när de väl initierats. Skillnaden är att du kan välja att initiera dem i en konstruktor, eller till ett värde som inte är känt förrän vid körning. Detta fungerar bara på fält. skrivskyddade fält kan antingen vara medlemmar av en instans eller statiska klassmedlemmar.

Kodblock

Lockiga klammerparenteser { ... } används för att beteckna ett kodblock och ett nytt omfång . Klassmedlemmar och kroppen av en metod är exempel på vad som kan leva inuti dessa hängslen i olika sammanhang.

Inuti metodkroppar kan du använda hängslen för att skapa nya scopes som så:

 

     

    
         
          
    

      
       
 void  DoSomething  ()  {  int  a  ;  {  int  b  ;  a  =  1  ;  }  a  =  2  ;  b  =  3  ;  // Kommer att misslyckas eftersom variabeln deklareras i ett inre scope.  } 

Programstruktur

AC#-applikationen består av klasser och deras medlemmar. Klasser och andra typer finns i namnutrymmen men kan också kapslas in i andra klasser.

Huvudmetod

Oavsett om det är en konsol eller en grafisk gränssnittsapplikation, måste programmet ha en ingångspunkt av något slag. Ingångspunkten för C#-applikationen är metoden som kallas Main . Det kan bara finnas en, och det är en statisk metod i en klass. Metoden returnerar vanligtvis void och skickas kommandoradsargument som en array av strängar.

   



  

 static  void  Main  (  sträng  []  args  )  {  }  // OR Main metod kan definieras utan parametrar.  statiskt  tomrum  Main  ()  {  } 

Huvudmetoden är också tillåten att returnera ett heltalsvärde om det anges.

   

     0
 static  int  Main  (  sträng  [ ]  args  )  {  return  ;  } 

Async Main

Detta är en funktion i C# 7.1.

Asynkrona uppgifter kan inväntas i huvudmetoden genom att deklarera att den returnerar typen Task .

    

     
 static  async  Task  Main  (  sträng  []  args  )  {  await  DoWorkAsync  (  42  );  } 

Alla kombinationer av Task , eller Task<int> och med eller utan parametern string[] args stöds.

Uttalanden på högsta nivå

Detta är en funktion i C# 9.0.

På samma sätt som i skriptspråk tar uttalanden på toppnivå bort ceremonin att behöva deklarera Programklassen med en Main- metod.

Istället kan uttalanden skrivas direkt i en specifik fil, och den filen kommer att vara ingångspunkten för programmet. Kod i andra filer måste fortfarande definieras i klasser.

Detta introducerades för att göra C# mindre omfattande och därmed mer tillgängligt för nybörjare att komma igång.

 

 använder  System  ;  Konsol  .  WriteLine  (  "Hej världen!"  ); 

Typer deklareras efter påståendena och blir automatiskt tillgängliga från påståendena ovanför dem.

Namnutrymmen

Namnområden är en del av ett typnamn och de används för att gruppera och/eller särskilja namngivna enheter från andra.

  System  .  IO  .  DirectoryInfo  // DirectoryInfo finns i System.IO-namnutrymmet 

Ett namnområde definieras så här:

 

    
 namnområde  FooNamespace  {  // Members  } 

använder direktiv

Användningsdirektivet laddar ett specifikt namnutrymme från en refererad sammansättning . Den placeras vanligtvis i toppen (eller rubriken) i en kodfil, men den kan placeras någon annanstans om så önskas, t.ex. i klasser. [ citat behövs ]

 
  använder  System  ;  använder  System.Collections  ; 

Direktivet kan också användas för att definiera ett annat namn för ett befintligt namnområde eller typ. Detta är ibland användbart när namn är för långa och mindre läsbara.

   
    använder  Net  =  System  .  Netto  ;  använder  DirInfo  =  System  .  IO  .  DirectoryInfo  ; 

använder statiskt direktiv

Det använda statiska direktivet laddar de statiska medlemmarna av en specificerad typ i det aktuella omfånget, vilket gör dem tillgängliga direkt med namnet på medlemmen.

  

 använder  statiskt  system  .  Konsol  ;  WriteLine  (  "Hej världen!"  ); 

Operatörer

Operatörskategori Operatörer
Aritmetisk + , - , * , / , %
Logisk (boolesk och bitvis) & , | , ^ , ! , ~ , && , || , sant , falskt
Strängsammansättning +
Öka, minska ++ , --
Flytta << , >>
Relationell (villkorlig) == , != , < , > , <= , >=
Uppdrag = , += , -= , *= , /= , %= , &= , |= , ^= , <<= , >>=
Medlemsåtkomst . , ?. , ?[]
Indexering []
Kasta ()
Villkorlig (ternär) ?:
Delegera sammanfogning och borttagning + , -
Objektskapande ny
Skriv information som , är , storlek på , typ av
Överflöde undantagskontroll markerad , okontrollerad
Inriktning och adress * , -> , [] , &
Växa samman ??
Lambda uttryck =>

Operatör överbelastning

Vissa av de befintliga operatörerna kan överbelastas genom att skriva en överbelastningsmetod.

      

        
 public  static  Foo  operator  +(  Foo  foo  ,  Bar  bar  )  {  return  new  Foo  (  foo  .  Value  +  bar  .  Value  );  } 

Dessa är de överbelastade operatörerna :

Operatörer
+ , - , ! , ~ , ++ , -- , sant , falskt Unära operatörer
+ , - , * , / , % , & , | , ^ , << , >> Binära operatorer
== , != , < , > , <= , >= Jämförelseoperatorer måste överbelastas i par
  • Tilldelningsoperatorer ( +=, *= etc.) är kombinationer av en binär operator och tilldelningsoperatorn ( = ) och kommer att utvärderas med de vanliga operatorerna, som kan överbelastas.
  • Cast-operatorer ( ( ) ) kan inte överbelastas, men du kan definiera konverteringsoperatorer.
  • Arrayindexeringsoperatorn ( [ ] ) är inte överbelastad, men du kan definiera nya indexerare.

Konverteringsoperatörer

Cast-operatorn är inte överbelastad men du kan skriva en konverteringsoperatormetod som lever i målklassen. Konverteringsmetoder kan definiera två varianter av operatorer, implicita och explicita konverteringsoperatorer. Den implicita operatören kommer att kasta utan att specificera med cast-operatören ( ( ) ) och den explicita operatören kräver att den används.

Implicit konverteringsoperatör

 

      

         
    
          
    


    class  Foo  {  public  int  Value  ;  public  static  implicit  operator  Foo  (  int  value  )  {  return  new  Foo  (  value  );  }  }  // Implicit konvertering  Foo  foo  =  2  ; 

Explicit konverteringsoperatör

 

      

         
    
          
    


    class  Foo  {  public  int  Value  ;  public  static  explicit  operator  Foo  (  int  value  )  {  return  new  Foo  (  value  );  }  }  // Explicit konvertering  Foo  foo  =  (  Foo  )  2  ; 

som operatör

As - operatören kommer att försöka göra en tyst cast till en given typ. Det kommer att returnera objektet som den nya typen om möjligt, och annars kommer det att returnera null.

   
      

       Stream  stream  =  Fil  .  Öppna  (  @"C:\Temp\data.dat" )  ;  FileStream  fstream  =  streama  som  FileStream  ;  // Kommer att returnera ett objekt.  String  str  =  ström  som  String  ;  // Returnerar null. 

Noll sammansmältningsoperatör

Detta är en funktion i C# 2.0 .

Det följande:

    returnera  ifNotNullValue  ??  annarsVärde  ; 

är en förkortning för:

        return  ifNotNullValue  !=  null  ?  ifNotNullValue  :  annarsValue  ; 

Det betyder att om innehållet i variabeln ifNotNullValue inte är null, kommer det innehållet att returneras, annars returneras innehållet i variabeln annarsValue .

C# 8.0 introducerar noll-koalescerande tilldelning, så att

   variabel  ??=  annarsVärde  ; 

är ekvivalent med

       if  (  variabeln  är  null  )  variabel  =  annarsVärde  ; 

Kontrollstrukturer

C# ärver de flesta av kontrollstrukturerna i C/C++ och lägger även till nya som foreach -satsen.

Villkorliga strukturer

Dessa strukturer styr programmets flöde genom givna förhållanden.

om uttalande

If - satsen anges när det givna villkoret är sant. Enkelradiga fallsatser kräver inte blockparenteser även om det oftast föredras av konventionen.

Enkelt påstående på en rad:

      om  (  i  ==  3  )  ...  ; 

Multi-line med else-block (utan några hängslen):

   
    

     om  (  i  ==  2  )  ...  annat  ... 

Rekommenderade kodningskonventioner för en if-sats.

   

    

    

    



    
 if  (  i  ==  3  )  {  ...  }  else  if  (  i  ==  2  )  {  ...  }  else  {  ...  } 

byta uttalande

Switchkonstruktionen fungerar som ett filter för olika värden . Varje värde leder till ett "case". Det är inte tillåtet att falla igenom ärendeavsnitt och därför används nyckelordet break vanligtvis för att avsluta ett ärende. En ovillkorlig retur i en ärendedel kan också användas för att avsluta ett ärende. Se också hur goto -satsen kan användas för att falla igenom från ett fall till ett annat. Många fall kan dock leda till samma kod. Standardfallet hanterar alla andra fall som inte hanteras av konstruktionen.

 

     
        
        
        
     
        
        
      
     
        
        
    
        
        
 switch  (  ch  )  {  case  'A'  :  statement  ;  ...  bryta  ;  fall  'B'  :  uttalande  ;  bryta  ;  case  'C'  :  // En switch-sektion kan ha flera case-etiketter.  fall  'D'  :  ...  bryta  ;  default  :  ...  break  ;  } 

Iterationsstrukturer

Iterationssatser är satser som exekveras upprepade gånger när ett givet villkor utvärderas som sant.

medan loop

   

    
 medan  (  i  ==  sant  )  {  ...  } 

gör ... medan loop





    gör  {  }  while  (  i  ==  sant  ); 

för slinga

For - loopen består av tre delar: deklaration , villkor och motuttryck . Vilken som helst av dem kan utelämnas eftersom de är valfria.

    0    

    
 för  (  int  i  =  ;  i  <  10  ;  i  ++)  {  ...  } 

Är likvärdig med denna kod representerad med en while- sats, förutom här är variabeln i inte lokal för slingan.

   0
   

    
    
 int  i  =  ;  while  (  i  <  10  )  {  //...  i  ++;  } 

varje slinga

Föreach - satsen är härledd från for -satsen och använder sig av ett visst mönster som beskrivs i C#s språkspecifikation för att erhålla och använda en uppräkning av element att iterera över.

Varje föremål i den givna samlingen kommer att returneras och nås i samband med kodblocket. När blockeringen har utförts kommer nästa artikel att returneras tills det inte finns några föremål kvar.

    

    
 foreach  (  int  i  i  intList  )  {  ...  } 

Hoppa uttalanden

Jump-satser ärvs från C/C++ och slutligen assemblerspråk genom det. De representerar helt enkelt jump-instruktionerna för ett assemblerspråk som styr flödet av ett program.

Etiketter och goto uttalande

Etiketter ges poäng i kod som kan hoppa till genom att använda goto -satsen.


    
      start  :  .......  goto  start  ; 

Observera att etiketten inte behöver placeras efter goto -satsen; det kan vara före det i källfilen.

Goto - satsen kan användas i switch -satser för att hoppa från ett fall till ett annat eller för att falla igenom från ett fall till nästa.

 

     
        
        
     
        
          
     
        
      
        
          
       
     
    
        
          
 switch  (  n  )  {  fall  1  :  Konsol  .  WriteLine  (  "Fall 1"  );  bryta  ;  fall  2  :  Konsol  .  WriteLine  (  "Fall 2"  );  goto  fall  1  ;  fall  3  :  Konsol  .  WriteLine  (  "Fall 3"  );  fall  4  :  // Kompileringen kommer att misslyckas här eftersom fall inte kan falla igenom i C#.  Konsol  .  WriteLine  (  "Fall 4"  );  goto  default  ;  // Detta är det korrekta sättet att gå vidare till nästa fall.  fall  5  :  // Flera etiketter för samma kod är OK  fall  6  :  default  :  Console  .  WriteLine  (  "Standard"  );  bryta  ;  // Även standard får inte nå slutpunkten  } 

bryta uttalande

Break - satsen bryter ut ur den närmaste loopen eller switch- satsen. Utförandet fortsätter i utlåtandet efter det avslutade utlåtandet, om sådant finns.

   
    0    

     
    
        
    
    
 int  e  =  10  ;  for  (  int  i  =  ;  i  <  e  ;  i  ++)  {  while  (  true  )  {  break  ;  }  // Kommer att bryta till denna punkt.  } 

fortsätta uttalandet

Fortsätt - satsen avbryter den aktuella iterationen av den aktuella kontrollsatsen och påbörjar nästa iteration.

 
     

   	   
      		    

   	
   	
 int  ch  ;  while  ((  ch  =  Konsol  .  Läs  ())  !=  -  1  )  {  if  (  ch  ==  ' '  )  fortsätt  ;  // Hoppar över resten av while-loopen  // Rest of while-loopen  ...  } 

While - slingan i koden ovan läser tecken genom att anropa GetChar () , och hoppar över satserna i slingans brödtext om tecknen är mellanslag.

Undantagshantering

Körtidsundantagshanteringsmetoden i C# ärvs från Java och C++.

Basklassbiblioteket har en klass som heter System . Undantag från vilket alla andra undantagsklasser är härledda. Ett Exception -objekt innehåller all information om ett specifikt undantag och även de inre undantag som orsakades. Programmerare kan definiera sina egna undantag genom att härleda från klassen Exception .

Ett undantag kan göras så här:

   kasta  nytt  NotImplementedException  (); 

försök ... fånga ... slutligen uttalanden

Undantag hanteras inom try ... catch blocks.



    
    

  

    
    



    
    
 prova  {  // Uttalanden som kan ge undantag  ...  }  catch  (  Undantag  ex  )  {  // Undantag fångas och hanteras här  ...  }  finally  {  // Utsagn exekveras alltid efter försök / fånga blocken  ...  } 

Uttrycken inom try- blocket exekveras, och om någon av dem ger ett undantag, avbryts exekveringen av blocket och undantaget hanteras av catch- blocket . Det kan finnas flera catch -block, i vilket fall det första blocket med en undantagsvariabel vars typ matchar typen av det kastade undantaget exekveras.

Om inget catch -block matchar typen av det kastade undantaget, avbryts exekveringen av det yttre blocket (eller metoden) som innehåller try ... catch- satsen, och undantaget skickas upp och utanför det innehållande blocket eller metoden. Undantaget sprids uppåt genom anropsstacken tills ett matchande fångstblock hittas inom en av de för närvarande aktiva metoderna. Om undantaget sprider sig hela vägen upp till den översta Main () -metoden utan att ett matchande fångstblock hittas, avslutas hela programmet och en textbeskrivning av undantaget skrivs till standardutgångsströmmen.

Satserna inom finally -blocket exekveras alltid efter försök och catch -blocken, oavsett om ett undantag har kastats eller inte. Sådana block är användbara för att tillhandahålla rensningskod.

Antingen ett fångstblock , ett slutligen block eller båda måste följa försöksblocket .

Typer

C# är ett statiskt skrivet språk som C och C++. Det betyder att varje variabel och konstant får en fast typ när den deklareras. Det finns två typer av typer: värdetyper och referenstyper .

Värdetyper

Förekomster av värdetyper finns på stacken, dvs de är bundna till sina variabler. Om du deklarerar en variabel för en värdetyp tilldelas minnet direkt. Om variabeln hamnar utanför räckvidden förstörs objektet med den.

Strukturer

Strukturer är mer kända som strukturer . Strukturer är användardefinierade värdetyper som deklareras med nyckelordet struct . De är väldigt lika klasser men är mer lämpade för lättviktstyper. Några viktiga syntaktiska skillnader mellan en klass och en struktur presenteras senare i den här artikeln .

 

    
 struct  Foo  {  ...  } 

De primitiva datatyperna är alla strukturer.

Fördefinierade typer

Dessa är de primitiva datatyperna.

Primitiva typer
Skriv namn BCL motsvarande Värde Räckvidd Storlek Standardvärde
sbyte System . SByte heltal −128 till +127 8-bitars (1-byte) 0
kort System . Int16 heltal −32 768 till +32 767 16-bitars (2-byte) 0
int System . Int32 heltal −2 147 483 648 till +2 147 483 647 32-bitars (4-byte) 0
lång System . Int64 heltal
−9 223 372 036 854 775 808 till +9 223 372 036 854 775 807
64-bitars (8-byte) 0
byte System . Byte osignerat heltal 0 till 255 8-bitars (1-byte) 0
kort System . UInt16 osignerat heltal 0 till 65 535 16-bitars (2-byte) 0
uint System . UInt32 osignerat heltal 0 till 4 294 967 295 32-bitars (4-byte) 0
lång System . UInt64 osignerat heltal 0 till 18 446 744 073 709 551 615 64-bitars (8-byte) 0
decimal System . Decimal undertecknat decimaltal
−79,228,162,514,264,337,593,543,950,335 till +79,228,162,514,264,337,593,543,950,335
128-bitars (16-byte) 0,0
flyta System . Enda flyttalnummer ±1,401298E−45 till ±3,402823E+38 32-bitars (4-byte) 0,0
dubbel System . Dubbel flyttalnummer
±4,94065645841246E−324 till ±1,79769313486232E+308
64-bitars (8-byte) 0,0
bool System . Boolean Boolean sant eller falskt 8-bitars (1-byte) falsk
röding System . Röding ett enda Unicode-tecken '\ u0000 ' till '\ uFFFF ' 16-bitars (2-byte) '\ u0000 '

Obs: sträng ( System . String ) är inte en struktur och är inte en primitiv typ.

Uppräkningar

Uppräknade typer (deklarerade med enum ) är namngivna värden som representerar heltalsvärden.

 

      0
      
      
      
          
 enum  Season  {  Winter  =  ,  Spring  =  1  ,  Summer  =  2  ,  Autumn  =  3  ,  Fall  =  Autumn  // Autumn is called Fall in American English.  } 

Enumvariabler initieras som standard till noll. De kan tilldelas eller initieras till de namngivna värdena som definieras av uppräkningstypen.

 
   Säsong  säsong  ;  säsong  =  Säsong  .  Vår  ; 

Variabler av enumtyp är heltalsvärden. Addition och subtraktion mellan variabler av samma typ är tillåtet utan någon specifik cast men multiplikation och division är något mer riskabelt och kräver en explicit cast. Cast krävs också för att konvertera enumvariabler till och från heltalstyper. Rollbesättningen ger dock inget undantag om värdet inte anges av typdefinitionen.

    
     
     
    

 
  säsong  =  (  Säsong  )  2  ;  // cast 2 till ett enum-värde av typen Season.  säsong  =  säsong  +  1  ;  // Lägger till 1 till värdet.  säsong  =  säsong  +  säsong2  ;  // Lägga till värdena för två enumvariabler.  int  värde  =  (  int  )  säsong  ;  // Kasta enum-värde till heltalsvärde.  säsong  ++;  // Säsong.Vår (1) blir Säsong.Sommar (2).  säsong  --;  // Säsong.Sommar (2) blir Säsong.Vår (1). 

Värden kan kombineras med hjälp av bitvis-OR-operatorn | .

        Färg  myColors  =  Färg  .  Grön  |  Färg  .  Gul  |  Färg  .  Blå  ; 

Referenstyper

Variabler som skapats för referenstyper är typade hanterade referenser. När konstruktorn anropas skapas ett objekt på högen och en referens tilldelas variabeln. När en variabel för ett objekt går utanför omfånget bryts referensen och när det inte finns några referenser kvar markeras objektet som skräp. Sopsamlaren kommer då snart att samla och förstöra den.

En referensvariabel är null när den inte refererar till något objekt.

Matriser

En matristyp är en referenstyp som refererar till ett utrymme som innehåller ett eller flera element av en viss typ. Alla arraytyper härrör från en gemensam basklass, System . Array . Varje element refereras av sitt index precis som i C++ och Java.

En array i C# är vad som skulle kallas en dynamisk array i C++.

    
0  
  
   0 int  []  siffror  =  new  int  [  2  ];  siffror  [  ]  =  2  ;  siffror  [  1  ]  =  5  ;  int  x  =  tal  [  ]; 
Initialiserare

Arrayinitierare tillhandahåller bekväm syntax för initiering av arrayer.


          

         

           // Lång syntax  int  []  tal  =  ny  int  [  5  ]{  20  ,  1  ,  42  ,  15  ,  34  };  // Kort syntax  int  []  tal2  =  {  20  ,  1  ,  42  ,  15  ,  34  };  // Utledd syntax  var  numbers3  =  new  []  {  20  ,  1  ,  42  ,  15  ,  34  }; 
Flerdimensionella arrayer

Matriser kan ha mer än en dimension, till exempel 2 dimensioner för att representera ett rutnät.

     
  

                 int  [,]  tal  =  new  int  [  3  ,  3  ];  siffror  [  1  ,  2  ]  =  2  ;  int  [,]  siffror2  =  nya  int  [  3  ,  3  ]  {  {  2  ,  3  ,  2  },  {  1  ,  2  ,  6  },  {  2  ,  4  ,  5  }  }; 

Se även

Klasser

Klasser är självbeskrivande användardefinierade referenstyper. I princip alla typer i .NET Framework är klasser, inklusive structs och enums, som är kompilatorgenererade klasser. Klassmedlemmar är privata som standard, men kan deklareras som offentliga för att vara synliga utanför klassen eller skyddas för att vara synliga av alla avkomlingar till klassen.

Strängar

Systemet . _ String class, eller helt enkelt string , representerar en oföränderlig sekvens av unicode-tecken ( char ).

Åtgärder som utförs på en sträng kommer alltid att returnera en ny sträng.

   
   0 
       string  text  =  "Hej världen!"  ;  string  substr  =  text  .  Delsträng  (  ,  5  );  sträng  []  delar  =  text  .  Split  (  nytt  char  []{  ' '  }); 

Systemet . _ StringBuilder- klassen kan användas när en föränderlig "sträng" önskas.

    


 var  sb  =  new  StringBuilder  ();  sb  .  Lägg till  (  'H'  );  sb  .  Lägg till  (  "el"  );  sb  .  AppendLine  (  "lo!"  ); 

Gränssnitt

Gränssnitt är datastrukturer som innehåller medlemsdefinitioner utan någon faktisk implementering. En variabel av en gränssnittstyp är en referens till en instans av en klass som implementerar detta gränssnitt. Se #Interfaces .

Delegater

C# tillhandahåller typsäkra objektorienterade funktionspekare i form av delegater .

 

    
         

         
    
           
    

         
    
           
    

      
    
        
           

        
              

          
             
    
 class  Program  {  // Delegat type:  delegate  int  Operation  (  int  a  ,  int  b  );  static  int  Add  (  int  i1  ,  int  i2  )  {  return  i1  +  i2  ;  }  static  int  Sub  (  int  i1  ,  int  i2  )  {  return  i1  -  i2  ;  }  static  void  Main  ()  {  // Instantiera delegaten och tilldela metoden till den.  Operation  op  =  Lägg till  ;  // Anropa metoden som delegaten pekar på.  int  resultat1  =  op  (  2  ,  3  );  // 5  op  =  Sub  ;  int  resultat2  =  op  (  10  ,  2  );  // 8  }  } 

Initiering av delegaten med en anonym metod.

            addition  =  delegat  (  int  a  ,  int  b  )  {  return  a  +  b  ;  }; 

Initiering av delegaten med lambda-uttryck.

        addition  =  (  a  ,  b  )  =>  a  +  b  ; 

evenemang

Händelser är pekare som kan peka på flera metoder. Mer exakt binder de metodpekare till en identifierare. Detta kan därför ses som en förlängning till delegater . De används vanligtvis som triggers i UI-utveckling. Formen som används i C# och resten av Common Language Infrastructure är baserad på den i klassiska Visual Basic .

     

    

       

    
     
    
          
    
 delegera  void  MouseEventHandler  (  objektavsändare  ,  MouseEventArgs  e  )  ;  offentlig  klass  Knapp  :  System  .  Windows  .  Kontroller  .  Styr  {  privat  händelse  MouseEventHandler  _onClick  ;  /* Imaginär triggerfunktion */  void  Klicka  ()  {  _onClick  (  detta  ,  nya  MouseEventArgs  (  data  ));  }  } 

En händelse kräver en åtföljd händelsehanterare som är gjord av en speciell delegat som i ett plattformsspecifikt bibliotek som i Windows Presentation Foundation och Windows Forms vanligtvis tar två parametrar: avsändare och händelseargumenten . Typen av händelseargument-objekt härrör från klassen EventArgs som är en del av CLI-basbiblioteket.

När den väl har deklarerats i sin klass är det enda sättet att åberopa händelsen inifrån ägaren. En lyssnarmetod kan implementeras utanför för att utlösas när händelsen avfyras.

    

      

     
    
           
          

        
          

        

    

         
    
        
    
 public  class  MainWindow  :  System  .  Windows  .  Kontroller  .  Window  {  privat  knapp  _button1  ;  public  MainWindow  ()  {  _button1  =  new  Button  ();  _knapp1  .  Text  =  "Klicka på mig!"  ;  /* Prenumerera på eventet */  _button1  .  ClickEvent  +=  Button1_OnClick  ;  /* Alternativ syntax som anses gammal:  _button1.MouseClick += new MouseEventHandler(Button1_OnClick); *   /  }  skyddad  void  Button1_OnClick  (  objektavsändare  ,  MouseEventArgs  e  )  {  MessageBox  .  Visa  (  "Klickat!"  );  }  } 

Anpassad eventimplementering är också möjlig:

	        

	   
	
		
		
			
			

			  
		
		
		
			
			

			  
		
	 privat  EventHandler  _clickHandles  =  (  s  ,  e  )  =>  {  };  public  event  EventHandler  Klicka på  {  add  {  // Viss kod som ska köras när hanteraren läggs till...  ...  _clickHandles  +=  värde  ;  }  remove  {  // Viss kod som ska köras när hanteraren tas bort...  ...  _clickHandles  -=  värde  ;  }  } 

Se även

Nullbara typer

Detta är en funktion i C# 2.0 .

Nullbara typer introducerades i C# 2.0 först för att göra det möjligt för värdetyper att vara null (användbart när man arbetar med en databas).

   
  

 int?  n  =  2  ;  n  =  noll  ;  Konsol  .  WriteLine  (  n  .  HasValue  ); 

I verkligheten är detta samma sak som att använda strukturen Nullable < T > .

   
  

 Nullbar  <  int  >  n  =  2  ;  n  =  noll  ;  Konsol  .  WriteLine  (  n  .  HasValue  ); 

Pekare

C# har och tillåter pekare till utvalda typer (vissa primitiver, enum, strängar, pekare och till och med arrayer och strukturer om de bara innehåller typer som kan pekas) i osäkra sammanhang: metoder och kodblock markerade som osäkra . Dessa är syntaktiskt desamma som pekare i C och C++. Runtime-checking är dock inaktiverad i osäkra block.

   

    
    
           
           a

         a 
           

        
        
        
     static  void  Main  (  sträng  []  args  )  {  osäker  {  int  a  =  2  ;  int  *  b  =  &a  ;  Konsol  .  WriteLine  (  "Adress till en: {0}. Värde: {1}",  (  int  )  &a  a  )  ;  Konsol  .  WriteLine  (  "Adress till b: {0}. Värde: {1}. Värde på *b: {2}" ,  (  int  )  &  b  ,  (  int  )  b  ,  *  b  );  //  Kommer att mata ut något i stil med:  // Adress till a: 71953600. Värde: 2  // Adress till b: 71953596. Värde: 71953600. Värde på *b: 2 }  } 

Strukturer krävs endast för att vara rena strukturer utan medlemmar av en hanterad referenstyp, t.ex. en sträng eller någon annan klass.

  

      
      


  

      
      
 public  struct  MyStruct  {  public  char  Character  ;  public  int  Heltal  ;  }  public  struct  MyContainerStruct  {  public  byte  Byte  ;  offentlig  MyStruct  MyStruct  ;  } 

I användning:

 
   

    MyContainerStruct  x  ;  MyContainerStruct  *  ptr  =  &  x  ;  byte  värde  =  ptr  ->  Byte  ; 

Dynamisk

Detta är en funktion i C# 4.0 och .NET Framework 4.0 .

Type dynamic är en funktion som möjliggör dynamisk runtime lookup till C# på ett statiskt sätt. Dynamisk betecknar en variabel med ett objekt med en typ som löses vid körning, i motsats till kompileringstid, som normalt görs.

Den här funktionen drar fördel av Dynamic Language Runtime (DLR) och har utformats specifikt med målet att samverka med dynamiskt typade språk som IronPython och IronRuby (implementationer av Python och Ruby för .NET).

Dynamiskt stöd underlättar också interoperationen med COM -objekt.

    
   dynamisk  x  =  ny  Foo  ();  x  .  Gör något  ();  // Kommer att kompileras och lösas vid körning. Ett undantag kommer att kastas om det är ogiltigt.  

Anonyma typer

Detta är en funktion i C# 3.0 .

Anonyma typer är namnlösa klasser som genereras av kompilatorn. De är bara förbrukningsbara och ändå mycket användbara i ett scenario som där du har en LINQ-fråga som returnerar ett objekt på select och du bara vill returnera några specifika värden. Sedan kan du definiera en anonym typ som innehåller automatiskt genererade skrivskyddade fält för värdena.

När en annan anonym typdeklaration instansieras med samma signatur antas typen automatiskt av kompilatorn.

            
             var  carl  =  new  {  Namn  =  "Carl"  ,  Ålder  =  35  };  // Namnet på typen är endast känt av kompilatorn.  var  mary  =  new  {  Namn  =  "Mary"  ,  Ålder  =  22  };  // Samma typ som uttrycket ovan 

Boxning och unboxning

Boxning är operationen att konvertera ett värde av en värdetyp till ett värde av en motsvarande referenstyp. Boxning i C# är implicit.

Unboxing är operationen att konvertera ett värde av en referenstyp (tidigare inramad) till ett värde av en värdetyp. Unboxing i C# kräver en explicit typ cast.

Exempel:

            
        
      int  foo  =  42  ;  // Värde typ.  objektstapel  =  foo  ;  _  // foo är boxad till bar.  int  foo2  =  (  int  )  bar  ;  // Unboxed tillbaka till värdetyp. 

Objektorienterad programmering (OOP)

C# har direkt stöd för objektorienterad programmering .

Föremål

Ett objekt skapas med typen som mall och kallas en instans av just den typen.

I C# är objekt antingen referenser eller värden. Ingen ytterligare syntaktisk skillnad görs mellan de i koden.

Objektklass

Alla typer, även värdetyper i sin inramade form, ärver implicit från systemet . Objektklass , den ultimata basklassen för alla objekt. Den här klassen innehåller de vanligaste metoderna som delas av alla objekt. Vissa av dessa är virtuella och kan åsidosättas.

Klasser ärver System . Objekt antingen direkt eller indirekt genom en annan basklass.


Medlemmar Några av medlemmarna i klassen Objekt:

  • Lika - Stöder jämförelser mellan objekt.
  • Slutför - Utför rensningsåtgärder innan ett objekt automatiskt återtas. (Standardförstörare)
  • GetHashCode - Hämtar numret som motsvarar värdet på objektet för att stödja användningen av en hashtabell.
  • GetType - Hämtar typen av den aktuella instansen.
  • ToString - Skapar en läsbar textsträng som beskriver en instans av klassen. Vanligtvis returnerar den namnet på typen.

Klasser

Klasser är grunderna i ett objektorienterat språk som C#. De fungerar som en mall för objekt. De innehåller medlemmar som lagrar och manipulerar data på ett verkligt sätt.

Skillnader mellan klasser och strukturer

Även om klasser och strukturer är lika i både sättet de deklareras och hur de används, finns det några betydande skillnader. Klasser är referenstyper och strukturer är värdetyper. En struktur allokeras på stacken när den deklareras och variabeln är bunden till sin adress. Den innehåller direkt värdet. Klasser är olika eftersom minnet är allokerat som objekt på högen. Variabler är snarare hanterade pekare på stacken som pekar på objekten. De är referenser.

Strukturer kräver lite mer arbete än klasser. Till exempel måste du uttryckligen skapa en standardkonstruktor som inte tar några argument för att initiera strukturen och dess medlemmar. Kompilatorn kommer att skapa en standard för klasser. Alla fält och egenskaper för en struktur måste ha initierats innan en instans skapas. Strukturer har inga finalizers och kan inte ärva från en annan klass som klasser gör. Däremot ärver de från System . ValueType , som ärver från System . Objekt . Strukturer är mer lämpade för mindre konstruktioner av data.

Detta är en kort sammanfattning av skillnaderna:

Standardkonstruktör Finaliserare Medlemsinitiering Arv
Klasser krävs inte (automatiskt genererad) ja inte nödvändig ja (om basklassen inte är förseglad )
Strukturer krävs (automatiskt genererad) Nej nödvändig stöds inte

Deklaration

En klass deklareras så här:

 

    
 klass  Foo  {  // Medlemsförklaringar  } 
Delklass
Detta är en funktion i C# 2.0 .

En partiell klass är en klassdeklaration vars kod är uppdelad i separata filer. De olika delarna av en delklass måste markeras med nyckelordet partiell .


  

    



  

    
 // File1.cs  partial  class  Foo  {  ...  }  // File2.cs  partial  class  Foo  {  ...  } 

Initialisering

Innan du kan använda medlemmarna i klassen måste du initialisera variabeln med en referens till ett objekt. För att skapa den ringer du till lämplig konstruktor med det nya nyckelordet. Den har samma namn som klassen.

     var  foo  =  ny  Foo  (); 

För strukturer är det valfritt att explicit anropa en konstruktor eftersom standarden anropas automatiskt. Du behöver bara deklarera det och det initieras med standardvärden.

Objektinitierare
Detta är en funktion i C# 3.0 .

Ger ett bekvämare sätt att initiera offentliga fält och egenskaper för ett objekt. Konstruktoranrop är valfria när det finns en standardkonstruktor.

    

      
      



    
  
   var  person  =  ny  person  {  Namn  =  "John Doe"  ,  ålder  =  39  };  // Lika med  var  person  =  ny  person  ();  person  .  Namn  =  "John Doe"  ;  person  .  Ålder  =  39  ; 
Samlingsinitierare
Detta är en funktion i C# 3.0 .

Samlingsinitierare ger en arrayliknande syntax för att initiera samlingar. Kompilatorn genererar helt enkelt anrop till Add-metoden. Detta fungerar för klasser som implementerar gränssnittet ICollection .

        


    



 var  list  =  new  List  <  int  >  {  2  ,  5  ,  6  ,  6  };  // Lika med  var  list  =  new  List  <  int  >();  lista  .  Lägg till  (  2  );  lista  .  Lägg till  (  5  );  lista  .  Lägg till  (  6  );  lista  .  Lägg till  (  6  ); 

Tillgång till medlemmar

Medlemmar av en instans och statiska medlemmar av en klass nås med hjälp av . operatör.


Åtkomst till en instansmedlem Instansmedlemmar kan nås genom namnet på en variabel.

   
    string  foo  =  "Hej"  ;  sträng  fooUpper  =  foo  .  Översta  (); 


Åtkomst till en statisk klassmedlem Statiska medlemmar nås genom att använda klassens namn eller annan typ.

     int  r  =  sträng  .  Jämför  (  foo  ,  fooUpper  ); 


Åtkomst till en medlem via en pekare I osäker kod nås medlemmar av ett värde (struct-typ) som refereras av en pekare med operatorn -> precis som i C och C++.

 
  
  
   
   PUNKT  p  ;  sid  .  X  =  2  ;  sid  .  Y  =  6  ;  PUNKT  *  ptr  =  &  p  ;  ptr  ->  Y  =  4  ; 

Modifierare

Modifierare är nyckelord som används för att ändra deklarationer av typer och typmedlemmar. Framför allt finns det en undergrupp som innehåller åtkomstmodifierarna.

Klassmodifierare
  • abstract - Anger att en klass endast fungerar som en basklass. Det måste implementeras i en ärvningsklass.
  • förseglad - Anger att en klass inte kan ärvas.
Klassmedlemsmodifierare
  • const - Anger att en variabel är ett konstant värde som måste initieras när den deklareras.
  • händelse - Deklarerar en händelse.
  • extern - Anger att en metodsignatur utan en kropp använder en DLL-import.
  • override - Anger att en metod- eller egenskapsdeklaration är en åsidosättande av en virtuell medlem eller en implementering av en medlem av en abstrakt klass.
  • readonly - Deklarerar ett fält som endast kan tilldelas värden som en del av deklarationen eller i en konstruktor i samma klass.
  • osäker - Anger ett osäkert sammanhang som tillåter användning av pekare.
  • virtual - Anger att en metod eller egenskapsdeklaration kan åsidosättas av en härledd klass.
  • volatile - Anger ett fält som kan modifieras av en extern process och förhindrar en optimerande kompilator från att modifiera användningen av fältet.
statisk modifierare

Den statiska modifieraren anger att en medlem tillhör klassen och inte till ett specifikt objekt. Klasser markerade som statiska får endast innehålla statiska medlemmar. Statiska medlemmar kallas ibland klassmedlemmar eftersom de gäller för klassen som helhet och inte för dess instanser.

  

       
    
        
    


 public  class  Foo  {  public  static  void  Something  ()  {  ...  }  }  // Anropar klassmetoden.  Foo  .  Något  (); 
Åtkomstmodifierare

Åtkomstmodifierarna , eller arvsmodifierarna , ställer in tillgängligheten för klasser, metoder och andra medlemmar . Något som är markerat för allmänheten kan nås var som helst. privata medlemmar kan endast nås från insidan av klassen de är deklarerade i och kommer att döljas när de ärvs. Medlemmar med den skyddade modifieraren kommer att vara privata , men tillgängliga när de ärvs. interna klasser och medlemmar kommer endast att vara tillgängliga från insidan av den deklarerande församlingen.

Klasser och strukturer är implicit interna och medlemmar är implicit privata om de inte har en åtkomstmodifierare.

  

      
    
         0
    

      
    

    
 public  class  Foo  {  public  int  Do  ()  {  return  ;  }  offentlig  klass  Bar  {  }  } 

Den här tabellen definierar var åtkomstmodifierarna kan användas.

Okapslade typer Medlemmar (inkl. kapslade typer)
offentlig ja ja
skyddad inre Nej ja
skyddad Nej ja
inre ja (standard) ja
privat skyddad Nej ja
privat Nej ja (standard)

Konstruktörer

En konstruktor är en speciell metod som anropas automatiskt när ett objekt skapas. Dess syfte är att initiera medlemmarna i objektet. Konstruktörer har samma namn som klassen och returnerar ingenting. De kan ta parametrar som vilken annan metod som helst.

 

    
    
        
    
 klass  Foo  {  Foo  ()  {  ...  }  } 

Konstruktörer kan vara offentliga , privata , skyddade eller interna .

Destruktör

Destruktören anropas när föremålet samlas upp av sophämtaren för att utföra en viss manuell sanering . Det finns en standard destructor-metod som heter finalize som kan åsidosättas genom att deklarera din egen.

Syntaxen liknar den för konstruktörer. Skillnaden är att namnet föregås av en ~ och det kan inte innehålla några parametrar. Det kan inte finnas mer än en förstörare.

 

    

    
    
        
    
 klass  Foo  {  ...  ~  Foo  ()  {  ...  }  } 

Finalister är alltid privata .

Metoder

Liksom i C och C++ finns det funktioner som grupperar återanvändbar kod. Den största skillnaden är att funktioner, precis som i Java, måste finnas i en klass. En funktion kallas därför en metod . En metod har ett returvärde, ett namn och vanligtvis några parametrar som initieras när den anropas med några argument. Den kan antingen tillhöra en instans av en klass eller vara en statisk medlem.

 

        
    
         
    
 class  Foo  {  int  Bar  (  int  a  ,  int  b  )  {  returnera  a  %  b  ;  }  } 

En metod kallas att använda . notation på en specifik variabel, eller som i fallet med statiska metoder, namnet på en typ.

    
    

 Foo  foo  =  ny  Foo  ();  int  r  =  foo  .  Bar  (  7  ,  2  );  Konsol  .  WriteLine  (  r  ); 
ref och ut parametrar

Man kan uttryckligen få argument att skickas genom referens när man anropar en metod med parametrar som föregås av nyckelord ref eller out . Dessa hanterade pekare är användbara när du skickar variabler som du vill ska modifieras i metoden genom referens. Den största skillnaden mellan de två är att en ut -parameter måste ha tilldelats inom metoden när metoden returnerar, medan ref inte behöver tilldela ett värde.

   

       
          

 
 

   

      

 
  void  PassRef  (  ref  int  x  )  {  if  (  x  ==  2  )  x  =  10  ;  }  int  Z  ;  PassRef  (  ref  Z  );  void  PassOut  (  ut  int  x  )  {  x  =  2  ;  }  int  Q  ;  PassOut  (  ut  Q  ); 
Valfria parametrar
Detta är en funktion i C# 4.0 .

C# 4.0 introducerar valfria parametrar med standardvärden som ses i C++. Till exempel:

       

      


   0
     
    void  Ökning  (  ref  int  x  ,  int  dx  =  1  )  {  x  +=  dx  ;  }  int  x  =  ;  Öka  (  ref  x  );  // dx tar standardvärdet 1  Increment  (  ref  x  ,  2  );  // dx tar värdet 2 

Dessutom, för att komplettera valfria parametrar, är det möjligt att explicit specificera parameternamn i metodanrop, vilket gör det möjligt att selektivt skicka en given delmängd av valfria parametrar för en metod. Den enda begränsningen är att namngivna parametrar måste placeras efter de icke namngivna parametrarna. Parameternamn kan anges för både valfria och obligatoriska parametrar, och kan användas för att förbättra läsbarheten eller godtyckligt ordna om argument i ett anrop. Till exempel:

      
      

 
   
   
     

 Streama  OpenFile  (  strängnamn  ,  FileMode  mode  =  FileMode  .  Open  ,  FileAccess  access  =  FileAccess  .  Läs  )  {  ...  }  OpenFile  (  "file.txt"  )  ;  // använd standardvärden för både "mode" och "access"  OpenFile  (  "file.txt"  ,  mode  :  FileMode  .  Create  );  // använd standardvärde för "access"  OpenFile  (  "file.txt"  ,  åtkomst  :  FileAccess  .  Läs  );  // använd standardvärde för "mode"  OpenFile  (  namn  :  "file.txt"  ,  åtkomst  :  FileAccess  .  Läs  ,  läge  :  FileMode  .  Skapa  );  // namnge alla parametrar för extra läsbarhet,  // och använd ordning som skiljer sig från metoddeklaration 

Valfria parametrar gör samverkan med COM enklare. Tidigare var C# tvungen att skicka in varje parameter i metoden för COM-komponenten, även de som är valfria. Till exempel:

   
   

 
         
         
         
         
         
 object  fileName  =  "Test.docx"  ;  objekt  saknas  =  System  .  Reflektion  .  Saknas  .  Värde  ;  doc  .  SaveAs  (  ref  filnamn  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ,  ref  saknas  ) ;  konsol  .  writeline  (  "Fil sparad framgångsrikt" )  ; 

Med stöd för valfria parametrar kan koden förkortas som

  doc  .  SaveAs  (  ref  filnamn  ); 
extern

En funktion i C# är möjligheten att anropa inbyggd kod. En metodsignatur deklareras helt enkelt utan brödtext och markeras som extern . Attributet DllImport måste också läggas till för att referera till den önskade DLL-filen.


       [DllImport("win32.dll")]  statisk  extern  dubbel  Pow  (  dubbel  a  ,  dubbel  b  ); 

Fält

Fält, eller klassvariabler , kan deklareras inuti klasskroppen för att lagra data.

 

     
 klass  Foo  {  double  foo  ;  } 

Fält kan initieras direkt när de deklareras (såvida de inte deklareras i struct).

 

       
 klass  Foo  {  double  foo  =  2,3  ;  } 

Modifierare för fält:

  • const - Gör fältet till en konstant.
  • privat - Gör fältet privat (standard).
  • skyddad - Gör fältet skyddat.
  • offentlig - Gör fältet offentligt.
  • readonly - Tillåter att fältet initieras endast en gång i en konstruktor.
  • statisk - Gör fältet till en statisk medlem.

Egenskaper

Egenskaper ger fältliknande syntax och kombinerar dem med kraften i metoder. En egenskap kan ha två accessorer: get och set .

  

      

     
    
            
             
    



    
   public  class  Person  {  privat  sträng  _namn  ;  sträng  Namn  {  get  {  return  _name  ;  }  set  {  _name  =  värde  ;  }  }  }  // Använda en egenskap  var  person  =  new  Person  ();  person  .  Namn  =  "Robert"  ; 

Modifierare för egenskaper:

  • privat - Gör egenskapen privat (standard).
  • skyddad - Gör egendomen skyddad.
  • offentlig - Gör fastigheten offentlig.
  • statisk - Gör egenskapen till en statisk medlem.

Modifierare för fastighetstillbehör:

  • privat – gör accessorn privat.
  • skyddad - Gör accessorn skyddad.
  • offentlig – gör accessorn offentlig.

Standardmodifierarna för accessorerna ärvs från egenskapen. Observera att accessorns modifierare endast kan vara lika eller mer restriktiva än egenskapens modifierare.

Automatiska egenskaper
Detta är en funktion i C# 3.0 .

En funktion i C# 3.0 är automatiskt implementerade egenskaper. Du definierar accessorer utan kroppar och kompilatorn genererar ett stödfält och den nödvändiga koden för accessorerna.

        public  double  Width  {  get  ;  privat  set  ;  } 

Indexerare

Indexerare lägger till arrayliknande indexeringsmöjligheter till objekt. De är implementerade på ett sätt som liknar fastigheter.

  

      

      
    
            
             
    



    
   intern  klass  IntList  {  privat  int  []  _items  ;  int  this  [  int  index  ]  {  get  {  return  _items  [  index  ];  }  set  {  _items  [  index  ]  =  värde  ;  }  }  }  // Använda en indexerare  var  list  =  new  IntList  ();  lista  [  2  ]  =  2  ; 

Arv

Klasser i C# får bara ärva från en klass. En klass kan härröra från vilken klass som helst som inte är markerad som förseglad .

 




   


 klass  A  {  }  klass  B  :  A  {  } 
virtuell

Metoder markerade som virtuella ger en implementering, men de kan åsidosättas av arvtagarna genom att använda nyckelordet åsidosätt .

Implementeringen väljs av den faktiska typen av objekt och inte typen av variabel.

 

       
    
         0
    


   

       
    
         
    
 class  Operation  {  public  virtual  int  Do  ()  {  return  ;  }  }  class  NewOperation  :  Operation  {  public  override  int  Do  ()  {  return  1  ;  }  } 
ny

När en icke-virtuell metod överbelastas med en annan signatur kan nyckelordet new användas. Den använda metoden kommer att väljas av typen av variabel istället för den faktiska typen av objektet.

 

      
    
         0
    


   

       
    
         
    
 class  Operation  {  public  int  Do  ()  {  return  ;  }  }  class  NewOperation  :  Operation  {  public  new  double  Do  ()  {  return  4.0  ;  }  } 

Detta visar fallet:

    


   

   


    var  operation  =  new  NewOperation  ();  // Kommer att anropa "double Do()" i NewOperation  double  d  =  operation  .  Gör  ();  Operation  operation_  =  operation  ;  // Kommer att anropa "int Do()" i Operation  int  i  =  operation_  .  Gör  (); 
abstrakt

Abstrakta klasser är klasser som endast fungerar som mallar och du kan inte initiera ett objekt av den typen. Annars är det precis som en vanlig klass.

Det kan också finnas abstrakta medlemmar. Abstrakta medlemmar är medlemmar i abstrakta klasser som inte har någon implementering. De måste åsidosättas av klassen som ärver medlemmen.

  

       


   

       
    

    

    
 abstrakt  klass  Mammal  {  offentlig  abstrakt  void  Walk  ();  }  klass  Människan  :  Mammal  {  public  override  void  Walk  ()  {  }  ...  } 
sluten

Den förseglade modifieraren kan kombineras med de andra som en valfri modifierare för klasser för att göra dem oärvbara.

   


 intern  förseglad  klass  Foo  {  } 

Gränssnitt

Gränssnitt är datastrukturer som innehåller medlemsdefinitioner och inte faktisk implementering. De är användbara när du vill definiera ett kontrakt mellan medlemmar i olika typer som har olika implementeringar. Du kan deklarera definitioner för metoder, egenskaper och indexerare. Gränssnittsmedlemmar är implicit offentliga. Ett gränssnitt kan antingen implicit eller explicit implementeras.

 

         
         

     
 gränssnitt  IBinaryOperation  {  double  A  {  get  ;  set  ;  }  dubbel  B  {  ;  set  ;  }  dubbel  GetResult  ();  } 

Implementera ett gränssnitt

Ett gränssnitt implementeras av en klass eller utökas med ett annat gränssnitt på samma sätt som du härleder en klass från en annan klass med : -notationen .

Implicit implementering

När ett gränssnitt implicit implementeras måste medlemmarna i gränssnittet vara offentliga .

    

          
          

      
    
           
    


    

          
          

      
    
           
    
 public  class  Adder  :  IBinaryOperation  {  public  double  A  {  get  ;  set  ;  }  offentlig  dubbel  B  {  get  ;  set  ;  }  public  double  GetResult  ()  {  return  A  +  B  ;  }  }  public  class  Multiplikator  :  IBinaryOperation  {  public  double  A  {  get  ;  set  ;  }  offentlig  dubbel  B  {  get  ;  set  ;  }  public  double  GetResult  ()  {  return  A  *  B  ;  }  } 

I användning:

   
 



   
  
  

   



   
  
  

    IBinaryOperation  op  =  null  ;  dubbelt  resultat  ;  // Adder implementerar gränssnittet IBinaryOperation.  op  =  ny  adderare  ();  op  .  A  =  2  ;  op  .  B  =  3  ;  resultat  =  op  .  GetResult  ();  // 5  // Multiplier implementerar också gränssnittet.  op  =  ny  multiplikator  ();  op  .  A  =  5  ;  op  .  B  =  4  ;  resultat  =  op  .  GetResult  ();  // 20 

Explicit implementering

Du kan också explicit implementera medlemmar. Medlemmarna i gränssnittet som är explicit implementerade av en klass är endast tillgängliga när objektet hanteras som gränssnittstyp.

    

         
         

     
    
           
    
 public  class  Adder  :  IBinaryOperation  {  double  IBinaryOperation  .  A  {  get  ;  set  ;  }  dubbel  IBinaryOperation  .  B  {  ;  set  ;  }  dubbel  IBinaryOperation  .  GetResult  ()  {  return  ((  IBinaryOperation  )  this  ).  A  +  ((  IBinaryOperation  )  detta  ).  B  ;  }  } 

I användning:

    







   
  
  

    Adder  add  =  new  Adder  ();  // Dessa medlemmar är inte tillgängliga:  // add.A = 2;  // add.B = 3;  // dubbelt resultat = add.GetResult();  // Casta till gränssnittstypen för att komma åt dem:  IBinaryOperation  add2  =  add  ;  lägg till 2  .  A  =  2  ;  lägg till 2  .  B  =  3  ;  dubbelt  resultat  =  add2  .  GetResult  (); 

Obs: Egenskaperna i klassen som utökar IBinaryOperation är automatiskt implementerade av kompilatorn och ett stödfält läggs till automatiskt (se #Automatiska egenskaper ) .

Utöka flera gränssnitt

Gränssnitt och klasser tillåts utöka flera gränssnitt.

    

    
 klass  MyClass  :  IInterfaceA  ,  IInterfaceB  {  ...  } 

Här är ett gränssnitt som utökar två gränssnitt.

    

    
 gränssnitt  IInterfaceC  :  IInterfaceA  ,  IInterfaceB  {  ...  } 

Gränssnitt kontra abstrakta klasser

Gränssnitt och abstrakta klasser liknar varandra. Följande beskriver några viktiga skillnader:

  • En abstrakt klass kan ha medlemsvariabler såväl som icke-abstrakta metoder eller egenskaper. Ett gränssnitt kan inte.
  • En klass eller abstrakt klass kan bara ärva från en klass eller abstrakt klass.
  • En klass eller abstrakt klass kan implementera ett eller flera gränssnitt.
  • Ett gränssnitt kan bara utöka andra gränssnitt.
  • En abstrakt klass kan ha icke-offentliga metoder och egenskaper (även abstrakta). Ett gränssnitt kan bara ha offentliga medlemmar.
  • En abstrakt klass kan ha konstanter, statiska metoder och statiska medlemmar. Ett gränssnitt kan inte.
  • En abstrakt klass kan ha konstruktorer. Ett gränssnitt kan inte.

Generika

Detta är en funktion i C# 2.0 och .NET Framework 2.0 .

Generika (eller parametriserade typer, parametrisk polymorfism ) använder typparametrar, som gör det möjligt att designa klasser och metoder som inte specificerar typen som används förrän klassen eller metoden instansierats. Den största fördelen är att man kan använda generiska typparametrar för att skapa klasser och metoder som kan användas utan att det kostar kostnaden för runtime casts eller boxningsoperationer, som visas här:



  

        


 

        
      
    
        
            

        
            

        
            
    
 // Deklarera den generiska klassen.  public  class  GenericList  <  T  >  {  void  Add  (  T  input  )  {  }  }  class  TestGenericList  {  private  class  ExampleClass  {  }  static  void  Main  ()  {  // Deklarera en lista av typen int.  var  list1  =  new  GenericList  <  int  >();  // Deklarera en lista av typen sträng.  var  list2  =  new  GenericList  <  string  >();  // Deklarera en lista av typen ExampleClass.  var  list3  =  new  GenericList  <  ExampleClass  >();  }  } 

Jämfört med C++-mallar kan generika C# ge ökad säkerhet, men har också något begränsade möjligheter. Det är till exempel inte möjligt att anropa aritmetiska operatorer på en C# generisk typ. Till skillnad från C++-mallar, instansieras .NET-parameteriserade typer under körning snarare än av kompilatorn; därför kan de vara tvärspråkiga medan C++-mallar inte kan. De stöder vissa funktioner som inte stöds direkt av C++-mallar, såsom typbegränsningar på generiska parametrar genom användning av gränssnitt. Å andra sidan stöder inte C# generiska parametrar av icke-typ.

Till skillnad från generika i Java använder .NET generics reifiering för att göra parameteriserade typer av förstklassiga objekt i Common Language Infrastructure (CLI) Virtual Machine, vilket möjliggör optimeringar och bevarande av typinformationen.

Använder generika

Generiska klasser

Klasser och strukturer kan vara generiska.

  

    
       
    
         
    


    

 public  class  List  <  T  >  {  ...  public  void  Add  (  T  item  )  {  ...  }  }  var  list  =  new  List  <  int  >();  lista  .  Lägg till  (  6  );  lista  .  Lägg till  (  2  ); 

Generiska gränssnitt

 

    
 gränssnitt  IEnumerable  <  T  >  {  ...  } 

Generiska delegater

        delegera  R  Func  <  T1  ,  T2  ,  R  >(  T1  a1  ,  T2  a2  ); 

Generiska metoder

      

          
     0
     
     


         
         
    

         
         
    


 public  static  T  []  CombineArrays  <  T  >(  T  []  a  ,  T  []  b  )  {  T  []  newArray  =  new  T  [  a  .  Längd  +  b  .  Längd  ];  a  .  CopyTo  (  newArray  ,  );  b  .  CopyTo  (  newArray  ,  a  .  Length  );  returnera  newArray  ;  }  sträng  []  a  =  ny  sträng  []  {  "a"  ,  "b"  ,  "c"  };  sträng  []  b  =  ny  sträng  []  {  "1"  ,  "2"  ,  "3"  };  sträng  []  c  =  CombineArrays  (  a  ,  b  );  dubbel  []  da  =  ny  dubbel  []  {  1,2  ,  2,17  ,  3,141592  };  dubbel  []  db  =  ny  dubbel  []  {  4,44  ,  5,6  ,  6,02  };  double  []  dc  =  CombineArrays  (  da  ,  db  );  // c är en strängmatris som innehåller { "a", "b", "c", "1", "2", "3"} // dc är en dubbelmatris som innehåller { 1.2, 2.17, 3.141592, 4.44  , 5,6, 6,02} 

Typparametrar

Typparametrar är namn som används i stället för betongtyper när man definierar en ny generisk. De kan associeras med klasser eller metoder genom att placera parametern type inom vinkelparenteser < > . När du instansierar (eller anropar) en generisk kan du sedan ersätta typparametern som du angav i dess deklaration med en konkret typ. Typparametrar kan begränsas genom att använda where och en begränsningsspecifikation, vilken som helst av de sex kommaseparerade begränsningarna kan användas:

Begränsning Förklaring
där T : struktur parametertyp måste vara en värdetyp
där T : klass typparameter måste vara en referenstyp
där T : ny () typparameter måste ha en konstruktor utan parametrar (måste visas sist)
där T : < basklass > typparameter måste ärva från < basklass >
där T : < gränssnitt > typparameter måste vara eller implementera detta gränssnitt
där T : U parameterbegränsning av naken typ

Samvarians och kontravarians

Detta är en funktion i C# 4.0 och .NET Framework 4.0 .

Generiska gränssnitt och delegater kan ha sina typparametrar markerade som kovarianta eller kontravarianta , med nyckelord ut respektive in . Dessa deklarationer respekteras sedan för typkonverteringar, både implicita och explicita, och både kompileringstid och körtid. Till exempel har det befintliga gränssnittet IEnumerable < T > omdefinierats enligt följande:

  

     
 gränssnitt  IEnumerable  <  ut  T  >  {  IEnumerator  <  T  >  GetEnumerator  ();  } 

Därför anses alla klasser som implementerar IEnumerable < Derived > för någon klass Derived också vara kompatibla med IEnumerable < Base > för alla klasser och gränssnitt Base that Derived utökar, direkt eller indirekt. I praktiken gör det det möjligt att skriva kod som:

  

        
    
        
    


    
  void  PrintAll  (  IEnumerable  <  object  >  objects  )  {  foreach  (  objekt  o  i  objekt  )  {  System  .  Konsol  .  WriteLine  (  o  );  }  }  IEnumerable  <  sträng  >  strängar  =  ny  lista  <  sträng  >();  PrintAll  (  strängar  );  // IEnumerable<string> konverteras implicit till IEnumerable<objekt> 

För kontravarians har det befintliga gränssnittet IComparer < T > omdefinierats enligt följande:

   

        
 public  interface  IComparer  <  in  T  >  {  int  Compare  (  T  x  ,  T  y  );  } 

Därför anses alla klasser som implementerar IComparer < Base > för någon klass Base också vara kompatibla med IComparer < Derived > för alla klasser och gränssnitt härledd som utökas från Base . Det gör det möjligt att skriva kod som:

   
    IComparer  <  object  >  objectComparer  =  GetComparer  ();  IComparer  <  string  >  stringComparer  =  objectComparer  ; 

Uppräknare

En enumerator är en iterator. Enumeratorer erhålls vanligtvis genom att anropa GetEnumerator () för ett objekt som implementerar IEnumerable -gränssnittet. Behållarklasser implementerar vanligtvis detta gränssnitt. Foreach -satsen i C# kan dock fungera på vilket objekt som helst som tillhandahåller en sådan metod, även om den inte implementerar IEnumerable . Detta gränssnitt utökades till en generisk version i .NET 2.0 .

Följande visar en enkel användning av iteratorer i C# 2.0:


   
 
    


    
     // explicit version  IEnumerator  <  MyType  >  iter  =  lista  .  GetEnumerator  ();  while  (  iter  .  MoveNext  ())  Konsol  .  WriteLine  (  iter  .  Current  );  // implicit version  foreach  (  MyType-  värde  i  listan  )  Console  .  WriteLine  (  värde  ); 

Generatorfunktionalitet

Detta är en funktion i C# 2.0 .

.NET 2.0 Framework gjorde det möjligt för C# att introducera en iterator som tillhandahåller generatorfunktionalitet , med hjälp av en avkastningskonstruktion . som liknar avkastningen i Python Med en avkastningsavkastning . behåller funktionen automatiskt sitt tillstånd under iterationen



    

        
    
           0
              
    



  

             
        
          
 // Metod som tar en iterabel inmatning (möjligen en array)  // och returnerar alla jämna tal.  public  static  IEnumerable  <  int  >  GetEven  (  IEnumerable  <  int  >  numbers  )  {  foreach  (  int  i  in  numbers  )  {  if  (  i  %  2  ==  )  yield  return  i  ;  }  }  // använder metoden för att endast mata ut jämna tal från arrayen  static  void  Main  ()  {  int  []  nummer  =  {  1  ,  2  ,  3  ,  4  ,  5  ,  6  };  foreach  (  int  i  i  GetEven  (  nummer  ))  Konsol  .  WriteLine  (  i  );  //utgångar 2, 4 och 6  } 

LINQ

Detta är en funktion i C# 3.0 och .NET Framework 3.0 .

LINQ, förkortning för Language Integrated Queries, är en .NET Framework-funktion som förenklar hanteringen av data. Främst lägger det till stöd som låter dig fråga arrayer, samlingar och databaser. Den introducerar också pärmar, vilket gör det lättare att komma åt databaser och deras data.

Fråga syntax

LINQ-frågesyntaxen introducerades i C# 3.0 och låter dig skriva SQL- liknande frågor i C#.

          

      
                
               var  list  =  new  List  <  int  >{  2  ,  7  ,  1  ,  3  ,  9  };  var  result  =  från  i  i  listan  där  i  >  1  välj  i  ; 

Satserna sammanställs till metodanrop, varvid nästan bara namnen på metoderna anges. Vilka metoder som i slutändan används bestäms av normal överbelastningsupplösning. Därmed påverkas slutresultatet av översättningen av vilka symboler som finns i omfattningen.

Det som skiljer sig från SQL är att från-satsen kommer först och inte sist som i SQL. Detta beror på att det verkar mer naturligt att skriva så här i C# [ citat behövs ] och stöder "Intellisense" (kodkomplettering i editorn).

Anonyma metoder

Anonyma metoder , eller i sin nuvarande form mer allmänt kallade "lambda-uttryck", är en funktion som låter dig skriva inline- stängningsliknande funktioner i din kod.

Det finns olika sätt att skapa anonyma metoder. Före C# 3.0 fanns det begränsat stöd genom att använda delegater.

Anonyma delegater

Detta är en funktion i C# 2.0 .

Anonyma delegater är funktionspekare som håller anonyma metoder. Syftet är att göra det enklare att använda delegater genom att förenkla processen för att tilldela funktionen. Istället för att deklarera en separat metod i kod kan programmeraren använda syntaxen för att skriva koden inline och kompilatorn kommer då att generera en anonym funktion för den.

            Func  <  int  ,  int  >  f  =  delegat  (  int  x  )  {  return  x  *  2  ;  }; 

Lambda uttryck

Detta är en funktion i C# 3.0 .

Lambda-uttryck ger en enkel syntax för inline-funktioner som liknar stängningar. Funktioner med parametrar härleder typen av parametrar om andra inte uttryckligen anges.




    
     
         


       


   0


           // [argument] => [metod-kropp]  // Med parametrar  n  =>  n  ==  2  (  a  ,  b  )  =>  a  +  b  (  a  ,  b  )  =>  {  a  ++;  returnera  a  +  b  ;  }  // Med explicit inskrivna parametrar  (  int  a  ,  int  b  )  =>  a  +  b  // Inga parametrar  ()  =>  return  // Tilldela lambda för att delegera  Func  <  int  ,  int  ,  int  >  f  =  (  a  ,  b  )  = >  a  +  b  ; 

Lambdor med flera uttalanden har kroppar omslutna av hängslen och inuti dem kan kod skrivas som i standardmetoder.

          (  a  ,  b  )  =>  {  a  ++;  returnera  a  +  b  ;  } 

Lambda-uttryck kan skickas som argument direkt i metodanrop som liknar anonyma delegater men med en mer estetisk syntax.

        var  list  =  stringList  .  Där  (  n  =>  n  .  Längd  >  2  ); 

Lambda-uttryck är i huvudsak kompilatorgenererade metoder som skickas via delegater. Dessa metoder är endast reserverade för kompilatorn och kan inte användas i något annat sammanhang.

Förlängningsmetoder

Detta är en funktion i C# 3.0 .

Extensionsmetoder är en form av syntaktisk socker som ger illusionen av att lägga till nya metoder till den befintliga klassen utanför dess definition. I praktiken är en förlängningsmetod en statisk metod som är anropbar som om den vore en instansmetod; mottagaren av samtalet är bunden till den första parametern i metoden, dekorerad med nyckelordet detta :

   

           
    
         0 
    


   
  public  static  class  StringExtensions  {  public  static  string  Left  (  denna  sträng  s  ,  int  n  )  {  return  s  .  Delsträng  (  ,  n  );  }  }  sträng  s  =  "foo"  ;  s  .  Vänster  (  3  );  // samma som StringExtensions.Left(s, 3); 

Lokala funktioner

Detta är en funktion i C# 7.0.

Lokala funktioner kan definieras i kroppen för en annan metod, konstruktor eller egenskaps getter och setter. Sådana funktioner har tillgång till alla variabler i det omslutande omfånget, inklusive lokala variabler för överordnad metod. De gäller för hela metoden, oavsett om de åberopas före eller efter deras deklaration. Åtkomstmodifierare (offentliga, privata, skyddade) kan inte användas med lokala funktioner. De stöder inte heller funktionsöverbelastning . Det betyder att det inte kan finnas två lokala funktioner i samma metod med samma namn även om signaturerna inte överlappar varandra. Efter en kompilering omvandlas en lokal funktion till en privat statisk metod, men när den är definierad kan den inte markeras som statisk.

I kodexemplet nedan är Sum-metoden en lokal funktion i Main-metoden. Så den kan endast användas inom sin överordnade metod Main:

   

        
    
           
    

     
    
 static  void  Main  (  sträng  []  args  )  {  int  Sum  (  int  x  ,  int  y  )  {  return  x  +  y  ;  }  Konsol  .  WriteLine  (  Summa  (  10  ,  20  ));  Konsol  .  ReadKey  ();  } 

Diverse

Förslutningsblock

C# implementerar stängningsblock med hjälp av satsen use . Use - satsen accepterar ett uttryck som resulterar i att ett objekt implementerar IDisposable , och kompilatorn genererar kod som garanterar objektets förfogande när omfattningen av use -satsen avslutas. Användningssatsen är syntaktisk socker . Det gör koden mer läsbar än motsvarande försök ... slutligen blockera.

  

        
    
        
          
        
    
 public  void  Foo  ()  {  using  (  var  bar  =  File  .  Open  (  "Foo.txt"  ))  {  // do some work  throw  new  Exception  ();  // bar kommer fortfarande att kasseras korrekt.  }  } 

Trådsynkronisering

C# tillhandahåller låssatsen , som är ytterligare ett exempel på nyttigt syntaktisk socker. Det fungerar genom att markera ett kodblock som en kritisk sektion genom ömsesidig uteslutning av åtkomst till ett tillhandahållet objekt. Liksom use -satsen fungerar den genom att kompilatorn genererar ett försök ... slutligen blockerar på sin plats.

   

  

     
    
        
        
    
 privat  statisk  StreamWriter  _writer  ;  public  void  ConcurrentMethod  ()  {  lock  (  _writer  )  {  _writer  .  WriteLine  (  "Linje 1."  );  _författare  .  WriteLine  (  "Följt av rad 2."  );  }  } 

Attribut

Attribut är entiteter av data som lagras som metadata i den kompilerade sammansättningen. Ett attribut kan läggas till typer och medlemmar som egenskaper och metoder. Attribut kan användas för bättre underhåll av preprocessor-direktiv.


  

    
          
 [CompilerGenerated]  public  class  $  AnonymousType  $  120  {  [CompilerGenerated]  public  string  Namn  {  get  ;  set  ;  }  } 

.NET Framework kommer med fördefinierade attribut som kan användas. Vissa av dem har en viktig roll under körning medan andra bara är för syntaktisk dekoration i kod som CompilerGenerated . Det markerar bara att det är ett kompilatorgenererat element. Programmerardefinierade attribut kan också skapas.

Ett attribut är i huvudsak en klass som ärver från systemet . Attributklass . Enligt konventionen slutar attributklasser med "Attribut" i deras namn. Detta kommer inte att krävas när du använder det.

    

       
    

    

      
    
          
    

          
 public  class  EdibleAttribute  :  Attribute  {  public  EdibleAttribute  ( )  :  base  ( )  {  }  public  EdibleAttribute  (  bool  isNotPoisonous  )  {  this  .  Är Giftig  =  !  är inte giftig  ;  }  public  bool  IsPoisonous  {  get  ;  set  ;  }  } 

Visar attributet som används med de valfria konstruktorparametrarna.


    

   
 [Ätbart(true)]  offentlig  klass  Peach  :  Fruit  {  // Members if any  } 

Förprocessor

C# har "förprocessordirektiv" (även om den inte har en faktisk förprocessor) baserat på C-förprocessorn som tillåter programmerare att definiera symboler , men inte makron. Villkor som #if , #endif och #else tillhandahålls också.

Direktiv som #region ger tips till redaktörer för kodvikning . #region - blocket måste avslutas med ett #endregion- direktiv.

  

    
      
       
    

    
        
        
        
    
 public  class  Foo  {  #region Constructors  public  Foo  ()  {}  public  Foo  (  int  firstParam  )  {}  #endregion  #region Metoder  public  void  IntBar  (  int  firstParam  )  {}  public  void  StrBar  (  string  firstParam  )  {}  public  void  BoolBar  (  bool  firstParam )   )  {}  #endregion  } 

Kodkommentarer

C# använder ett dubbelt snedstreck ( // ) för att indikera att resten av raden är en kommentar.

  

    
           
 public  class  Foo  {  // a comment  public  static  void  Bar  (  int  firstParam  )  {}  // Also a comment  } 

Kommentarer med flera rader kan indikeras med ett inledande snedstreck/asterisk ( /* ) och en slutstjärna/snedstreck ( */ ).

  

    

         
 public  class  Foo  { /* En   kommentar med  flera rader */   public  static  void  Bar  (  int  firstParam  )  {}  } 

Kommentarer kapslar inte. Det här är två enskilda kommentarer:

// Kan lägga /* */ */ */ /* /*
/* Kan sätta /* /* /* men det slutar med */

Enradskommentarer som börjar med tre snedstreck används för XML-dokumentation. Detta är dock en konvention som används av Visual Studio och är inte en del av språkdefinitionen:

    
    
     /// <sammanfattning>  /// Den här klassen är väldigt stilig.  /// </sammanfattning> 

XML-dokumentationssystem

C#s dokumentationssystem liknar Javas Javadoc , men baserat på XML . Två metoder för dokumentation stöds för närvarande av C# -kompilatorn .

Enradsdokumentationskommentarer, som de som vanligtvis finns i Visual Studio- genererad kod, indikeras på en rad som börjar med /// .

  

    
    
    
         
 public  class  Foo  {  /// <summary>En sammanfattning av metoden.</summary>  /// <param name="firstParam">En beskrivning av parametern.</param>  /// <remarks>Anmärkningar om metod.</remarks>  public  static  void  Bar  (  int  firstParam  )  {}  } 

Flerradiga dokumentationskommentarer, även om de definieras i språkspecifikationen för version 1.0, stöddes inte förrän .NET 1.1-versionen. Dessa kommentarer betecknas med ett startande snedstreck/asterisk/asterisk ( /** ) och ett slutande asterisk/framåt snedstreck ( */ ).

  

    


         
 public  class  Foo  {  /** <summary>En sammanfattning av metoden.</summary>  * <param name="firstParam">En beskrivning av parametern.</param>  * <remarks>Anmärkningar om metoden.</ anmärkningar> */  public  static  void  Bar  (  int  firstParam  )  {}  } 

tekniken snedstreck/asterisk/asterisk ( /** ).

Detta kodblock:



 /**  * <summary>  * En sammanfattning av metoden.</summary>*/ 

producerar en annan XML-kommentar än detta kodblock:



 /**  * <summary>  En sammanfattning av metoden.</summary>*/ 

Syntax för dokumentationskommentarer och deras XML- uppmärkning definieras i en icke-normativ bilaga till ECMA C#-standarden. Samma standard definierar också regler för bearbetning av sådana kommentarer, och deras omvandling till ett vanligt XML- dokument med exakta regler för kartläggning av Common Language Infrastructure (CLI)-identifierare till deras relaterade dokumentationselement. Detta gör att vilken C# -integrerad utvecklingsmiljö (IDE) eller annat utvecklingsverktyg som helst kan hitta dokumentation för vilken symbol som helst i koden på ett visst väldefinierat sätt.

Syntax för asynkron väntan

Detta är en funktion i C# 5.0 och .NET Framework 4.0 .

Från och med .NET Framework 4 finns ett uppgiftsbibliotek som gör det lättare att skriva parallella och flertrådade applikationer genom uppgifter.

C# 5.0 har stöd för asynkront modersmål.

Tänk på den här koden som drar fördel av uppgiftsbiblioteket direkt:

   

       
    
            
           
               
             
        
    


     
       


 public  static  class  SomeAsyncCode  {  public  static  Task  <  XDocument  >  GetContentAsync (  )  {  var  httpClient  =  new  HttpClient (  );  returnera  httpClient  .  GetStringAsync  (  "https://www.contoso.com/"  ).  ContinueWith  ((  task  )  =>  {  string  responseBodyAsText  =  uppgift  .  Resultat  ;  returnera  XDocument  .  Parse  (  responseBodyAsText  );  });  }  }  var  t  =  SomeAsyncCode  .  GetContentAsync  ().  ContinueWith  ((  task  )  =>  {  var  xmlDocument  =  uppgift  .  Resultat  ;  });  t  .  Start  (); 

Här är samma logik skriven i syntaxen för async-await :

   

        
    
            
            
         
    


    

 public  static  class  SomeAsyncCode  {  public  static  async  Task  <  XDocument  >  GetContentAsync  ()  {  var  httpClient  =  new  HttpClient  ();  string  responseBodyAsText  =  await  httpClient  .  GetStringAsync  (  "https://www.contoso.com/"  );  returnera  XDocument  .  Parse  (  responseBodyAsText  );  }  }  var  xmlDocument  =  await  SomeAsyncCode  .  GetContentAsync  ();  // Uppgiften kommer att startas på samtal med avvakta. 

Dialekter

Spec#

Spec# är en dialekt av C# som utvecklas parallellt med standardimplementeringen från Microsoft. Det utökar C# med specifikationsspråksfunktioner och är en möjlig framtida funktion till C#-språket. Den lägger också till syntax för kodkontrakts-API:et som introducerades i .NET Framework 4.0 . Spec# utvecklas av Microsoft Research .

Detta exempel visar två av de grundläggande strukturerna som används när du lägger till kontrakt till din kod.

   
       0

        
    

    
 static  void  Main  (  sträng  ![]  args  )  kräver  args  .  Length  >  {  foreach  (  sträng  arg  i  args  )  {  }  } 
  • ! används för att göra en referenstyp icke-nullbar, t.ex. kan du inte ställa in värdet till null. Detta i motsats till null-typer som tillåter värdetyper att ställas in som null.
  • kräver anger ett villkor som måste följas i koden. I det här fallet får längden på args inte vara noll eller mindre.

Ej nullbara typer

Spec# utökar C# med icke-nullbara typer som helt enkelt kontrollerar så att variablerna för nullbara typer som har satts som icke-nullbara inte är null. Om är null kommer ett undantag att kastas.

     sträng  !  inmatning 

I användning:

  

    
 offentligt  test  (  sträng  !  input  )  {  ...  } 

Förutsättningar

Förutsättningarna kontrolleras innan en metod exekveras.

  
       0

      
 public  Test  (  int  i  )  kräver  i  >  ;  {  det här  .  i  =  i  ;  } 

Postvillkor

Postvillkor är villkor som säkerställs att vara korrekta när en metod har exekverats.

  
       0

    
 public  void  Increment  ()  säkerställer  i  >  ;  {  i  ++;  } 

Markerade undantag

Spec# lägger till markerade undantag som de i Java .

  
      

    
 public  void  DoSomething  ()  kastar  SomeException  ;  // SomeException : ICheckedException  {  ...  } 

Markerade undantag är problematiska, eftersom när en funktion på lägre nivå lägger till en ny undantagstyp, måste hela kedjan av metoder som använder denna metod på någon kapslad lägre nivå också ändra sitt kontrakt. Detta bryter mot principen öppet/stängt .

Se även

  1.   Archer, Tom (2001). Inuti C# . Microsoft Press. ISBN 0-7356-1288-9 .
  2. Bart de Smet på Spec#

externa länkar