Granska .NET-typsystemet

Slutförd

C# är ett starkt skrivet språk. Varje variabel och konstant har en typ, liksom varje uttryck som utvärderas till ett värde. .NET-klassbiblioteket definierar inbyggda numeriska typer och komplexa typer som representerar en mängd olika konstruktioner. Dessa konstruktioner omfattar filsystemet, nätverksanslutningar, samlingar och matriser med objekt och datum. Ett typiskt C#-program använder typer från klassbiblioteket och användardefinierade typer som modellerar de begrepp som är specifika för programmets problemdomän.

Inbyggda typer

C# tillhandahåller en standarduppsättning med inbyggda typer. Dessa standardtyper representerar heltal, flyttalsvärden, booleska uttryck, texttecken, decimalvärden och andra typer av data. Det finns också inbyggda sträng- och objekttyper. Dessa typer är tillgängliga för dig att använda i valfritt C#-program.

Anpassade typer

Du använder konstruktionerna struct, class, interface, enumoch record för att skapa egna anpassade typer. Själva .NET-klassbiblioteket är en samling anpassade typer som du kan använda i dina egna program. Som standard är de vanligaste typerna i klassbiblioteket tillgängliga i alla C#-program. Andra blir bara tillgängliga när du uttryckligen lägger till en projektreferens till sammansättningen som definierar dem. När kompilatorn har en referens till sammansättningen kan du deklarera variabler (och konstanter) av de typer som deklareras i sammansättningen i källkoden.

Vanligt typsystem

Det är viktigt att förstå två grundläggande punkter om typsystemet i .NET:

  • Den stöder arvsprincipen. Typer kan härledas från andra typer, så kallade bastyper. Den härledda typen ärver (med vissa begränsningar) metoderna, egenskaperna och andra medlemmar av bastypen. Bastypen kan i sin tur härledas från någon annan typ, i vilket fall den härledda typen ärver medlemmarna i båda bastyperna i arvshierarkin. Alla typer, inklusive inbyggda numeriska typer som System.Int32 (C#-nyckelord: int), härleds slutligen från en enda bastyp, vilket är System.Object (C#-nyckelord: object). Den här enhetliga typhierarkin kallas för Common Type System (CTS).

  • Varje typ i CTS definieras som antingen en värdetyp eller en referenstyp. Dessa typer innehåller alla anpassade typer i .NET-klassbiblioteket och även dina egna användardefinierade typer. Typer som du definierar med hjälp av nyckelordet struct är värdetyper. alla inbyggda numeriska typer är structs. Typer som du definierar med hjälp av nyckelordet klass eller post är referenstyper. Referenstyper och värdetyper har olika kompileringstidsregler och olika körningsbeteenden.

Följande bild visar relationen mellan värdetyper och referenstyper i CTS.

Diagram som visar värde- och referenstyper.

Klasser och strukturer är två av de grundläggande konstruktionerna i det gemensamma typsystemet i .NET. Var och en är i princip en datastruktur som kapslar in en uppsättning data och beteenden som hör ihop som en logisk enhet. Data och beteenden är medlemmar i class, structeller record. Medlemmarna i en klass innehåller egenskaper (data), metoder (beteenden), fält (variabler som deklareras i klassen) och många andra.

En class, struct, eller record-deklaration är som en ritning som används för att skapa instanser eller objekt vid körningstid. Om du definierar en klass med namnet Personär Person namnet på typen. Om du deklarerar och initierar en variabel p av typen Personsägs p vara ett objekt eller en instans av Person. Flera instanser av samma Person typ kan skapas och varje instans kan ha olika värden i sina egenskaper och fält.

En klass är en referenstyp. När ett objekt av typen skapas innehåller variabeln som objektet tilldelas endast en referens till det minnet. När objektreferensen tilldelas till en ny variabel refererar den nya variabeln till det ursprungliga objektet. Ändringar som görs via en variabel återspeglas i den andra variabeln eftersom de båda refererar till samma data.

En struct är en värdetyp. När en struct skapas, innehåller variabeln, till vilken struct tilldelas, de faktiska data för struct. När struct tilldelas till en ny variabel kopieras datavärdet. Den nya variabeln och den ursprungliga variabeln innehåller därför två separata kopior av samma data. Ändringar som görs i en kopia påverkar inte den andra kopian.

Posttyper kan vara antingen referenstyper (record class) eller värdetyper (record struct). Posttyper innehåller metoder som stöder värdejämlikhet.

I allmänhet används klasser för att modellera mer komplexa beteenden. Klasser lagrar vanligtvis data som är avsedda att ändras när ett klassobjekt har skapats. Strukturer passar bäst för små datastrukturer. Strukturer lagrar vanligtvis data som inte är avsedda att ändras när struct har skapats. Posttyper är datastrukturer med andra kompilatorsyntetiserade medlemmar. Poster lagrar vanligtvis data som inte är avsedda att ändras när objektet har skapats.

Värdetyper

Värdetyper härleds från System.ValueType, som härleds från System.Object. Typer som härleds från System.ValueType har ett särskilt beteende i Common Language Runtime. Värdetypsvariabler innehåller direkt deras värden. Minnet för en struct allokeras direkt i det sammanhang där variabeln deklareras. Det finns ingen separat heapallokering eller skräpinsamlingskostnader för värdetypsvariabler. Du kan deklarera poststrukturer som är värdetyper och inkludera de syntetiserade medlemmarna för rekord.

Det finns två kategorier av värdetyper: struct och enum.

De inbyggda numeriska typerna är structs och de har fält och metoder som du kan komma åt:


// constant field on type byte.
byte b = byte.MaxValue;

Men du deklarerar och tilldelar värden till dem som om de vore enkla icke-aggregerade typer:


byte num = 0xA;
int i = 5;
char c = 'Z';

Värdetyper är förseglade. Du kan inte härleda en typ från någon värdetyp, till exempel System.Int32. Du kan inte definiera en struct att ärva från någon användardefinierad class eller struct eftersom en struct bara kan ärva från System.ValueType.

Du använder nyckelordet struct för att skapa dina egna anpassade värdetyper. Vanligtvis används en struct som en container för en liten uppsättning relaterade variabler, som du ser i följande exempel:


public struct Coords
{
    public int x, y;

    public Coords(int p1, int p2)
    {
        x = p1;
        y = p2;
    }
}

Den andra kategorin av värdetyper är enum. En enum definierar en uppsättning namngivna integralkonstanter. Till exempel innehåller System.IO.FileMode uppräkning i .NET-klassbiblioteket en uppsättning namngivna konstanta heltal som anger hur en fil ska öppnas. Syntaxen för en enum visas i följande exempel:


public enum FileMode
{
    CreateNew = 1,
    Create = 2,
    Open = 3,
    OpenOrCreate = 4,
    Truncate = 5,
    Append = 6,
}

Konstanten System.IO.FileMode.Create har värdet 2. Namnet är dock mycket mer meningsfullt för människor som läser källkoden, och därför är det bättre att använda uppräkningar i stället för konstanta literalnummer.

Alla enums ärver från System.Enum, som ärver från System.ValueType. Alla regler som gäller för structs gäller även för enums.

Referenstyper

Typerna class, record, delegate, arrayoch interface är referenstyper.

När du deklarerar en variabel av en referenstyp innehåller den värdet null tills du tilldelar den med en instans av den typen eller skapar en med operatorn new.

I följande exempel visas hur du deklarerar referenstypvariabler med hjälp av matriser:


// Declaring an array variable
int[] numbers;

// Initializing the array with a size of 5
numbers = new int[5];

// Alternatively, declaring and initializing an array in one line
int[] numbers2 = new int[] { 1, 2, 3, 4, 5 };

// Assigning a reference to another variable
int[] numbers3 = numbers2;

Operatorn new skapar en instans av typen och returnerar en referens till den instansen. Referensen är objektets minnesadress och den referensen lagras i variabeln. När du tilldelar en referenstypvariabel till en annan variabel kopierar du referensen, inte själva objektet. Båda variablerna refererar till samma objekt i minnet.

Not

Förutom att vara referenstyper är matriser samlingar. Samlingar kan initieras med samlingsuttryck, vilket eliminerar kravet på att inkludera nyckelordet new när du deklarerar och initierar en matris på en rad. Till exempel: int[] numbers = [ 1, 2, 3, 4, 5 ];.

Du kan skapa en instans av en klass med samma syntax som används för att instansiera de inbyggda typerna. I följande exempel visas hur du skapar en instans av en klass:


MyClass myClass = new MyClass();
MyClass myClass2 = myClass;

Operatorn new skapar en instans av klassen och returnerar en referens till den instansen. Referensen är objektets minnesadress och den referensen lagras i variabeln. När du tilldelar en referenstypvariabel till en annan variabel kopierar du referensen, inte själva objektet. Båda variablerna refererar till samma objekt i minnet.