Delen via


Het C#-typesysteem

Aanbeveling

Nieuw bij het ontwikkelen van software? Begin eerst met de handleiding Aan de slag. Ze begeleiden u bij het schrijven van programma's en introduceren geleidelijk verschillende soorten.

Ervaren in een andere taal? Als u al typesystemen begrijpt, skipt u het verschil tussen waarde en referentie en de gids kies welk type, en ga dan naar de artikelen over specifieke typen.

C# is een sterk getypte taal. Elke variabele, constante en expressie heeft een type. De compiler dwingt typeveiligheid af door te controleren of elke bewerking in uw code geldig is voor de betrokken typen. U kunt bijvoorbeeld twee int waarden toevoegen, maar u kunt geen int en een 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;

Opmerking

In tegenstelling tot C en C++, in C#, bool is niet converteerbaar naar int.

Typeveiligheid vangt fouten op tijdens het compileren, voordat uw code wordt uitgevoerd. De compiler sluit ook typegegevens in het uitvoerbare bestand in als metagegevens, die de COMMON Language Runtime (CLR) gebruikt voor aanvullende veiligheidscontroles tijdens runtime.

Variabelen declareren met typen

Wanneer u een variabele declareert, geeft u het type expliciet op of gebruikt var om de compiler het type te laten afleiden van de toegewezen waarde:

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

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

Methodeparameters en retourwaarden hebben ook typen. De volgende methode gebruikt een string en een int, en retourneert een string:

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

Nadat u een variabele hebt gedeclareerd, kunt u het type niet wijzigen of een waarde toewijzen die niet compatibel is met het gedeclareerde type. U kunt waarden converteren naar andere typen. De compiler voert impliciete conversies uit die gegevens niet automatisch verliezen. Voor expliciete conversies (casts ) moet u de conversie in uw code aangeven. Zie Cast- en typeconversies voor meer informatie.

Ingebouwde typen en aangepaste typen

C# biedt ingebouwde typen voor algemene gegevens: gehele getallen, drijvendekommagetallen, boolen charstring. Elk C#-programma kan deze ingebouwde typen gebruiken zonder extra verwijzingen.

Naast ingebouwde typen kunt u uw eigen typen maken met behulp van verschillende constructies:

  • Klassen : referentietypen voor modelleringsgedrag en complexe objecten. Ondersteuning voor overname en polymorfisme.
  • Structs : waardetypen voor kleine, lichtgewicht gegevens. Elke variabele heeft een eigen kopie.
  • Records : klassen of structs met door compiler gegenereerde gelijkheid, ToStringen niet-destructieve mutatie via with expressies.
  • Interfaces — Contracten die de leden definiëren die elke klasse of struct kunnen implementeren.
  • Opsommingen : benoemde sets integrale constanten, zoals dagen van de week of bestandstoegangsmodi.
  • Tuples : lichtgewicht structurele typen die gerelateerde waarden groeperen zonder een benoemd type te definiëren.
  • Algemene functies : typeparameterconstructies zoals List<T> en Dictionary<TKey, TValue> die typeveiligheid bieden terwijl dezelfde logica voor verschillende typen wordt hergebruikt.

Waardetypen en verwijzingstypen

Elk type in C# is een waardetype of een verwijzingstype. Dit onderscheid bepaalt hoe variabelen gegevens opslaan en hoe toewijzing werkt.

Waardetypen bevatten hun gegevens rechtstreeks. Wanneer u een waardetype toewijst aan een nieuwe variabele, kopieert de runtime de gegevens. Wijzigingen in de ene variabele zijn niet van invloed op de andere. Structs, opsommingen en de ingebouwde numerieke typen zijn alle waardetypen.

Referentietypen bevatten een verwijzing naar een object op de beheerde heap. Wanneer u een verwijzingstype toewijst aan een nieuwe variabele, wijzen beide variabelen naar hetzelfde object. Wijzigingen via de ene variabele zijn zichtbaar via de andere. Klassen, arrays, delegaten en tekenreeksen zijn verwijzingstypen.

In het volgende voorbeeld ziet u het verschil. Het eerste blok toont de definitie voor de Coords recordstruct, een waardetype. Het tweede blok toont het verschillende gedrag voor waardetypen en verwijzingstypen.

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

Alle typen zijn uiteindelijk afgeleid van System.Object. Waardetypen zijn afgeleid van System.ValueType, dat is afgeleid van object. Deze geïntegreerde hiërarchie wordt het Common Type System (CTS) genoemd. Zie Overname voor meer informatie over overname.

Kies welk type

Wanneer u een nieuw type definieert, bepaalt het type dat u kiest hoe uw code zich gedraagt. Gebruik de volgende richtlijnen om een eerste beslissing te nemen:

  • Tuple : tijdelijke groepering van waarden die geen benoemd type of gedrag nodig hebben.
  • struct of record struct — Kleine gegevens (ongeveer 64 bytes of minder), waardesemantiek of onveranderbaarheid. Recordstructs voegen gelijkheid en with expressies op basis van waarden toe.
  • record class — Voornamelijk gegevens, met gelijkheid op basis van waarde, ToStringen niet-destructieve mutatie. Ondersteunt overname.
  • class — Complex gedrag, polymorfisme of veranderlijke toestand. De meeste aangepaste typen zijn klassen.
  • interface — Een contract dat niet-gerelateerde typen kan implementeren. Definieert mogelijkheden in plaats van identiteit.
  • enum — Een vaste set benoemde constanten, zoals statuscodes of opties.

Meer dan één optie is vaak redelijk.

Type compileertijd en runtime-type

Een variabele kan verschillende typen hebben tijdens het compileren en runtime. Het compileertijdtype is het gedeclareerde of afgeleide type in de broncode. Het runtimetype is het werkelijke type van het exemplaar waarnaar de variabele verwijst. Het run-timetype moet hetzelfde zijn als het compileertimetype, of een type dat daarvan is afgeleid of dat het type implementeert. Een toewijzing is alleen geldig wanneer er een impliciete conversie bestaat van het runtimetype naar het compile-tijdtype, zoals een identiteit, verwijzing, omsluiten of numerieke conversie.

// 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";

In het voorgaande voorbeeld heeft boxed een type tijdens de compilatie van object, maar een runtimetype van string. De opdracht werkt omdat string afkomstig is van object. characters heeft een compile-tijdtype van IEnumerable<char>, en de toewijzing werkt omdat string die interface implementeert. Het compileertijdtype bepaalt de overbelastingsresolutie en beschikbare conversies. Het runtimetype bepaalt het verzenden van virtuele methoden, is expressies en switch expressies.

Zie ook

C#-taalspecificatie

Zie de C#-taalspecificatie voor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.