A C# típusú rendszer

Jótanács

Új szoftverfejlesztés? Először az Első lépések oktatóanyagokkal kezdje. Végigvezetik a programok írásán, és fokozatosan ismertetik a különböző típusokat.

Tapasztalt egy másik nyelven? Ha már ismeri a típusrendszereket, gyorsan olvassa át az érték- és a hivatkozástípusok közötti különbséget, valamint az útmutatót a típusfajta kiválasztásához, majd ugorjon az adott típusokkal kapcsolatos cikkekre.

A C# egy erősen gépelt nyelv. Minden változónak, állandónak és kifejezésnek van típusa. A fordító a típusbiztonságot úgy kényszeríti ki, hogy ellenőrzi, hogy a kód minden művelete érvényes-e az érintett típusokra. Hozzáadhat például két int értéket, de nem adhat hozzá egy int és egy 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;

Megjegyzés:

A C és a C++ nyelvtől eltérően a C# nyelvben a bool nem alakítható át int típusra.

A típusbiztonság hibákat fog fordítási időben, még a kód futtatása előtt. A fordító emellett metaadatokként ágyazza be a típusadatokat a végrehajtható fájlba, amelyeket a közös nyelvi futtatókörnyezet (CLR) a futásidőben végzett további biztonsági ellenőrzésekhez használ.

Változók deklarálása típusokkal

Amikor deklarál egy változót, explicit módon adja meg annak típusát, vagy lehetővé var teszi, hogy a fordító a hozzárendelt értékből következtetsen a típusra:

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

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

A metódusparamétereknek és a visszaadott értékeknek is vannak típusai. A következő metódus egy string és egy int, és visszaad egy string-t.

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

A változó deklarálása után nem módosíthatja annak típusát, és nem rendelhet hozzá olyan értéket, amely nem kompatibilis a deklarált típussal. Az értékeket más típusokra is konvertálhatja. A fordító implicit konverziókat hajt végre, amelyek nem veszítik el automatikusan az adatokat. Az explicit konverziók (castek) megkövetelik, hogy jelezze a konverziót a kódban. A további információért lásd: Kasztolás és típuskonverziók.

Beépített típusok és egyéni típusok

A C# beépített típusokat biztosít a gyakori adatokhoz: egész számokhoz, lebegőpontos számokhoz, boolés charstring. Minden C#-program további hivatkozások nélkül használhatja ezeket a beépített típusokat.

A beépített típusokon kívül több szerkezettel is létrehozhat saját típusokat:

  • Osztályok – Referenciatípusok modellezési viselkedéshez és összetett objektumokhoz. Támogatja az öröklést és a polimorfizmust.
  • Szerkezetek – Kis méretű, egyszerűsített adatok értéktípusai. Minden változó saját másolatot tartalmaz.
  • Rekordok – Osztályok vagy struktúrák fordító által generált egyenlőséggelToString, és megőrző jellegű mutáció kifejezéseken keresztülwith.
  • Interfészek – Szerződések, amelyek meghatározzák azokat a tagokat, amelyeket bármely osztály vagy szerkezet implementálhat.
  • Számbavételek – Az integrál állandók nevesített készletei, például a hét napjai vagy a fájlhozzáférési módok.
  • Tuples – Egyszerűsített szerkezeti típusok, amelyek névvel ellátott típus definiálása nélkül csoportosítják a kapcsolódó értékeket.
  • Generics – Típusparaméteres szerkezetek, például List<T>Dictionary<TKey, TValue> típusbiztonságot biztosítanak, miközben ugyanazt a logikát használja újra a különböző típusok esetében.

Értéktípusok és referenciatípusok

A C# minden típusa értéktípus vagy referenciatípus. Ez a különbség határozza meg, hogy a változók hogyan tárolják az adatokat, és hogyan működnek a hozzárendelések.

Az értéktípusok közvetlenül tárolják az adataikat. Amikor értéktípust rendel egy új változóhoz, a futtatókörnyezet átmásolja az adatokat. Az egyik változó módosítása nincs hatással a másikra. A szerkezetek, enumerálások és a beépített numerikus típusok mind értéktípusok.

A referenciatípusok a felügyelt halom egy objektumára mutató hivatkozást tárolnak. Amikor egy referenciatípust rendel egy új változóhoz, mindkét változó ugyanarra az objektumra mutat. Az egyik változó módosításai a másikon keresztül láthatók. Az osztályok, tömbök, delegátusok és karakterláncok referenciatípusok.

Az alábbi példa a különbséget mutatja be. Az első blokk a rekordstruktúra definícióját Coords jeleníti meg, amely értéktípus. A második blokk az értéktípusok és referenciatípusok eltérő viselkedését mutatja be.

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

Minden típus végső soron a System.Object-ből származik. Az értéktípusok a System.ValueType-ból származnak, amely a object-ből származik. Ezt az egyesített hierarchiát common type system (CTS) néven nevezik. További információ az öröklésről: Öröklés.

Válassza ki, hogy milyen típusú

Amikor új típust határoz meg, a kód viselkedésének megfelelő alakzatokat választ. A kezdeti döntéshez használja az alábbi irányelveket:

  • Tulajdon – Olyan értékek ideiglenes csoportosítása, amelyhez nincs szükség névvel ellátott típusra vagy viselkedésre.
  • struct vagy record struct – Kis méretű adatok (nagyjából 64 bájt vagy annál kisebb), értékszemantika vagy megváltoztathatatlanság. A rekordstruktúra értékalapú egyenlőséget és with kifejezéseket ad hozzá.
  • record class — Elsősorban az értékalapú egyenlőséget ToStringés a nem strukturált mutációt tartalmazó adatok. Támogatja az öröklést.
  • class — Összetett viselkedés, polimorfizmus vagy mutable állapot. A legtöbb egyedi típus osztály.
  • interface – Olyan szerződés, amelyet a nem kapcsolódó típusok megvalósíthatnak. Identitás helyett képességeket határoz meg.
  • enum — Elnevezett állandók rögzített készlete, például állapotkódok vagy beállítások.

Több lehetőség is gyakran ésszerű.

Fordítási idő típusa és futásideje típusa

A változók fordítási és futási időben eltérő típusokkal rendelkezhetnek. A fordítási idő típusa a forráskód deklarált vagy kikövetkezett típusa. A futási idő típusa annak a példánynak a tényleges típusa, amelyre a változó hivatkozik. A futásidejű típusnak meg kell egyeznie a fordítási idő típusával, vagy egy olyan típusnak, amely abból származik vagy implementálja azt. A hozzárendelés csak akkor érvényes, ha implicit átalakítás létezik a futásidejű típustól a fordítási idő típusig, például identitás, hivatkozás, boxing vagy numerikus átalakítás.

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

Az előző példában boxed fordítási időben a object típusú, azonban futási időben a string típusú. A hozzárendelés azért működik, mert string a következőből objectszármazik: . Hasonlóképpen, characters fordítási idejű típusú IEnumerable<char>, és a hozzárendelés működik, mert string implementálja azt az interfészt. A fordítási idő típus szabályozza a túlterhelés feloldását és a rendelkezésre álló átalakításokat. A futásidejű típus szabályozza a virtuális metódusok küldését, is kifejezéseit és switch kifejezéseit.

Lásd még

C# nyelvspecifikáció

További információkért lásd a C# nyelvi specifikációját. A nyelvi specifikáció a C#-szintaxis és -használat végleges forrása.