Dela via


C#-typsystemet

Tips/Råd

Är du nybörjare på att utveckla programvara? Börja med självstudierna Komma igång först. De vägleder dig genom att skriva program och introducera datatyper när du går.

Har du erfarenhet av ett annat språk? Om du redan förstår typsystem, skummar du igenom skillnaden mellan värde och referens och väljer vilken typ av vägledning, och går sedan vidare till artiklarna om specifika typer.

C# är ett starkt skrivet språk. Varje variabel, konstant och uttryck har en typ. Kompilatorn framtvingar typsäkerhet genom att kontrollera att varje åtgärd i koden är giltig för de typer som berörs. Du kan till exempel lägga till två int värden, men du kan inte lägga till ett int och ett bool:

int a = 5;
int b = a + 2; // OK

bool test = true;

// Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'.
// int c = a + test;

Anmärkning

Till skillnad från C och C++, i C#, bool är inte konvertibla till int.

Typsäkerhet fångar fel vid kompileringstillfället innan koden körs. Kompilatorn bäddar också in typinformation i den körbara filen som metadata, som CLR (Common Language Runtime) använder för ytterligare säkerhetskontroller vid körning.

Deklarera variabler med typer

När du deklarerar en variabel anger du dess typ explicit eller använder var för att låta kompilatorn härleda typen från det tilldelade värdet:

// Explicit type:
int count = 10;
double temperature = 36.6;

// Compiler-inferred type:
var name = "C#";
var items = new List<string> { "one", "two", "three" };

Metodparametrar och returvärden har också typer. Följande metod tar en string och en int, och returnerar en string:

static string GetGreeting(string name, int visitCount)
{
    return visitCount switch
    {
        1 => $"Welcome, {name}!",
        _ => $"Welcome back, {name}! Visit #{visitCount}."
    };
}

När du har deklarerat en variabel kan du inte ändra dess typ eller tilldela ett värde som inte är kompatibelt med den deklarerade typen. Du kan konvertera värden till andra typer. Kompilatorn utför implicita konverteringar som inte förlorar data automatiskt. Explicita konverteringar (casts) kräver att du anger konverteringen i koden. För mer information, se Konvertering och typomvandlingar.

Inbyggda typer och anpassade typer

C# innehåller inbyggda typer för vanliga data: heltal, flyttalsnummer, bool, charoch string. Varje C#-program kan använda dessa inbyggda typer utan några extra referenser.

Utöver inbyggda typer kan du skapa dina egna typer med hjälp av flera konstruktioner:

  • Klasser – Referenstyper för modelleringsbeteende och komplexa objekt. Stöd arv och polymorfism.
  • Structs – Värdetyper för små, lätta data. Varje variabel innehåller en egen kopia.
  • Records – Klasser eller structs med kompilatorgenererad likhet, ToString, och icke-förstörande mutation genom with uttryck.
  • Gränssnitt – Kontrakt som definierar medlemmar som vilken klass eller struct som helst kan implementera.
  • Uppräkningar – Namngivna uppsättningar med integralkonstanter, till exempel veckodagar eller filåtkomstlägen.
  • Tupplar – Lätta strukturella typer som grupperar relaterade värden utan att definiera en namngiven typ.
  • Generics – typparameteriserade konstruktioner som List<T> och Dictionary<TKey, TValue> som ger typsäkerhet samtidigt som samma logik återanvänds för olika typer.

Värdetyper och referenstyper

Varje typ i C# är antingen en värdetyp eller en referenstyp. Den här skillnaden avgör hur variabler lagrar data och hur tilldelning fungerar.

Värdetyperna innehåller sina data direkt. När du tilldelar en värdetyp till en ny variabel kopierar körmiljön data. Ändringar i en variabel påverkar inte den andra. Strukturer, uppräkningstyper och de inbyggda numeriska typerna är alla värdetyper.

Referenstyper innehåller en referens till ett objekt på den hanterade heapen. När du tilldelar en referenstyp till en ny variabel pekar båda variablerna på samma objekt. Ändringar via den ena variabeln visas genom den andra. Klasser, matriser, ombud och strängar är referenstyper.

I följande exempel visas skillnaden. Det första blocket visar definitionen för Coords-poststrukt, som är en värdetyp. Det andra blocket visar olika beteende för värdetyper och referenstyper.

public readonly record struct Coords(int X, int Y);
// Value type: each variable holds its own copy
var point1 = new Coords(3, 4);
var point2 = point1;
Console.WriteLine($"point1: ({point1.X}, {point1.Y})");
Console.WriteLine($"point2: ({point2.X}, {point2.Y})");
// point1 and point2 are independent copies

// Reference type: both variables refer to the same object
var list1 = new List<int> { 1, 2, 3 };
var list2 = list1;
list2.Add(4);
Console.WriteLine($"list1 count: {list1.Count}"); // 4 — same object

Alla typer härleds slutligen från System.Object. Värdetyper härleds från System.ValueType, som härleds från object. Den här enhetliga hierarkin kallas för CTS (Common Type System ). Mer information om arv finns i Arv.

Välj vilken typ av typ

När du definierar en ny typ, den typ som du väljer former hur koden beter sig. Använd följande riktlinjer för att fatta ett första beslut:

  • Tuppeln – Tillfällig gruppering av värden som inte behöver någon namngiven typ eller ett namngivet beteende.
  • struct eller record struct – Små data (ungefär 64 byte eller mindre), värdesemantik eller oföränderlighet. Poststrukturer lägger till värdebaserad likhet och with uttryck.
  • record class — Primärt data, med värdebaserad likhet, ToString, och icke-förstörande mutation. Stöder arv.
  • class — Komplext beteende, polymorfism eller föränderligt tillstånd. De flesta anpassade typer är klasser.
  • interface — Ett kontrakt som orelaterade typer kan implementera. Definierar funktioner i stället för identitet.
  • enum – En fast uppsättning namngivna konstanter, till exempel statuskoder eller alternativ.

Mer än ett alternativ är ofta rimligt.

Kompileringstidstyp och körningstyp

En variabel kan ha olika typer vid kompileringstid och körningstid. Kompileringstidstypen är den deklarerade eller härledda typen i källkoden. Körningstidtypen är den faktiska typen av instans som variabeln refererar till. Köretidstypen måste vara densamma som kompileringstypen, eller en typ som härleds från den eller implementerar den. En tilldelning är endast giltig när det finns en implicit konvertering från körningstypen till kompileringstidstypen, till exempel en identitet, referens, boxning eller numerisk konvertering.

// Compile-time and run-time types match:
string message = "Hello, world!";

// Compile-time type differs from run-time type:
object boxed = "This is a string at run time";
IEnumerable<char> characters = "abcdefghijklmnopqrstuvwxyz";

I det föregående exemplet har boxed en kompileringstidstyp av object men en körningstidstyp av string. Tilldelningen fungerar eftersom string härleds från object. På samma sätt har characters en kompileringstidstyp på IEnumerable<char>, och tilldelningen fungerar eftersom string implementerar det gränssnittet. Kompileringstidstypen kontrollerar överlagringsupplösning och tillgängliga konverteringar. Körningstidstypen styr metodsändning av virtuella metoder, is uttryck och switch uttryck.

Se även

Språkspecifikation för C#

Mer information finns i C#-språkspecifikationen. Språkspecifikationen är den slutgiltiga källan för C#-syntax och -användning.