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
på
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
decimal |
23456 , [ 0. . 9 ]+
|
---|---|
hexadecimal |
0 0 xF5 , x [ 0. . 9 , A..F , a..f ] + _ _ _
|
binär |
0 00 b010110001101 , b [ , 1 ]+
|
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 , ...
|
röding |
'a' , 'Z' , '\ u0231 ' , '\ x30 ' , '\n'
|
---|
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}!"
|
---|
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 { få ; 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 { få ; 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
- Archer, Tom (2001). Inuti C# . Microsoft Press. ISBN 0-7356-1288-9 .
- Bart de Smet på Spec#