Typy a členy

Jako objektově orientovaný jazyk jazyk C# podporuje koncepty zapouzdření, dědičnosti a polymorfismu. Třída může dědit přímo z jedné nadřazené třídy a může implementovat libovolný počet rozhraní. Metody, které přepíší virtuální metody v nadřazené třídě, vyžadují klíčové slovo jako override způsob, jak se vyhnout náhodnému opětovnému definování. V jazyce C# je struktura jako odlehčená třída. Jedná se o typ přidělený zásobníkem, který může implementovat rozhraní, ale nepodporuje dědičnost. Jazyk C# také poskytuje záznamy, což jsou typy tříd, jejichž účelem je primárně ukládání datových hodnot.

Třídy a objekty

Třídy jsou nejzásácnější z typů jazyka C#. Třída je datová struktura, která kombinuje stav (pole) a akce (metody a další členy funkce) v jedné jednotce. Třída poskytuje definici pro instance třídy, označované také jako objekty. Třídy podporují dědičnost a polymorfismus, mechanismy, kdy odvozené třídy mohou rozšířit a specializovat základní třídy.

Nové třídy se vytvářejí pomocí deklarací tříd. Deklarace třídy začíná hlavičkou. Hlavička určuje:

  • Atributy a modifikátory třídy
  • Název třídy
  • Základní třída (při dědění ze základní třídy)
  • Rozhraní implementovaná třídou .

Za hlavičkou následuje tělo třídy, která se skládá ze seznamu deklarací členů napsaných mezi oddělovači a { } .

Následující kód ukazuje deklaraci jednoduché třídy s názvem Point :

public class Point
{
    public int X { get; }
    public int Y { get; }
    
    public Point(int x, int y) => (X, Y) = (x, y);
}

Instance tříd jsou vytvořeny pomocí operátoru , který přiděluje paměť pro novou instanci, vyvolá konstruktor pro inicializaci instance a vrátí odkaz new na instanci. Následující příkazy vytvoří dva Point objekty a uloží odkazy na tyto objekty do dvou proměnných:

var p1 = new Point(0, 0);
var p2 = new Point(10, 20);

Paměť zabírá objekt je automaticky uvolněna, když už objekt není dostupný. V jazyce C# není nutné ani možné explicitně udělovat objekty.

Parametry typu

Obecné třídy definují parametry typu. Parametry typu jsou seznam názvů parametrů typu uzavřených v hranatých závorkách. Parametry typu se budou řídit názvem třídy. Parametry typu lze poté použít v těle deklarací třídy k definování členů třídy. V následujícím příkladu jsou parametry typu Pair a TFirst TSecond :

public class Pair<TFirst, TSecond>
{
    public TFirst First { get; }
    public TSecond Second { get; }
    
    public Pair(TFirst first, TSecond second) => 
        (First, Second) = (first, second);
}

Typ třídy, který je deklarován pro přecházování parametrů typu, se nazývá obecný typ třídy. Struktury, rozhraní a typy delegátů mohou být také obecné. Při použití obecné třídy je nutné zadat argumenty typu pro každý z parametrů typu:

var pair = new Pair<int, string>(1, "two");
int i = pair.First;     // TFirst int
string s = pair.Second; // TSecond string

Obecný typ s argumenty typu, jak je uvedeno Pair<int,string> výše, se nazývá konstruovaný typ.

Základní třídy

Deklarace třídy může určit základní třídu. Za parametry názvu třídy a typu zadejte dvojtečku a název základní třídy. Vynechání specifikace základní třídy je stejné jako odvození z typu object . V následujícím příkladu je základní třída Point3D třídy Point . V prvním příkladu je základní třída Point třídy object :

public class Point3D : Point
{
    public int Z { get; set; }
    
    public Point3D(int x, int y, int z) : base(x, y)
    {
        Z = z;
    }
}

Třída dědí členy své základní třídy. Dědičnost znamená, že třída implicitně obsahuje téměř všechny členy své základní třídy. Třída nezdědí instanci a statické konstruktory a finalizační metodu. Odvozená třída může k zděděným členům přidat nové členy, ale nemůže odebrat definici zděděného členu. V předchozím příkladu dědí členy a z a každá instance obsahuje tři vlastnosti Point3D X , a Y Point Point3D X Y Z .

Implicitní převod existuje z typu třídy na kterýkoli z jejích typů základní třídy. Proměnná typu třídy může odkazovat na instanci této třídy nebo na instanci jakékoli odvozené třídy. Například na deklaraci předchozí třídy může proměnná typu odkazovat buď na , Point Point nebo na Point3D :

Point a = new Point(10, 20);
Point b = new Point3D(10, 20, 30);

Struktury

Třídy definují typy, které podporují dědičnost a polymorfismus. Umožňují vytvářet sofistikovaná chování založená na hierarchiích odvozených tříd. Naopak typy struktur jsou jednodušší typy, jejichž primárním účelem je ukládání datových hodnot. Struktury nedeklarují základní typ. Implicitně se odvozují z System.ValueType . Z typu nelze struct odvodit jiné struct typy. Jsou implicitně zapečetěné.

public struct Point
{
    public double X { get; }
    public double Y { get; }
    
    public Point(double x, double y) => (X, Y) = (x, y);
}

Rozhraní

Rozhraní * _ definuje kontrakt, který lze implementovat pomocí tříd a struktur. Definujete soubor _interface*, který deklaruje možnosti, které jsou sdíleny mezi různými typy. Například rozhraní definuje konzistentní způsob, jak procházet všechny položky v System.Collections.Generic.IEnumerable<T> kolekci, například pole. Rozhraní může obsahovat metody, vlastnosti, události a indexery. Rozhraní obvykle neposkytuje implementace členů, které definuje – pouze určuje členy, které musí být zadány třídami nebo strukturami, které implementují rozhraní.

Rozhraní mohou využívat vícenásobné dědičnosti. V následujícím příkladu rozhraní IComboBox dědí z i ITextBox IListBox .

interface IControl
{
    void Paint();
}

interface ITextBox : IControl
{
    void SetText(string text);
}

interface IListBox : IControl
{
    void SetItems(string[] items);
}

interface IComboBox : ITextBox, IListBox { }

Třídy a struktury mohou implementovat více rozhraní. V následujícím příkladu třída EditBox implementuje i IControl IDataBound .

interface IDataBound
{
    void Bind(Binder b);
}

public class EditBox : IControl, IDataBound
{
    public void Paint() { }
    public void Bind(Binder b) { }
}

Pokud třída nebo struktura implementuje určité rozhraní, instance této třídy nebo struktury lze implicitně převést na tento typ rozhraní. Například

EditBox editBox = new EditBox();
IControl control = editBox;
IDataBound dataBound = editBox;

Výčty

Typ výčtu definuje sadu konstantních hodnot. Následující kód enum deklaruje konstanty, které definují různé kořenové kořeny:

public enum SomeRootVegetable
{
    HorseRadish,
    Radish,
    Turnip
}

Můžete také definovat , enum který se má použít v kombinaci jako příznaky. Následující deklarace deklaruje sadu příznaků pro čtyři období. Můžete použít jakoukoli kombinaci období, včetně hodnoty, All která zahrnuje všechny období:

[Flags]
public enum Seasons
{
    None = 0,
    Summer = 1,
    Autumn = 2,
    Winter = 4,
    Spring = 8,
    All = Summer | Autumn | Winter | Spring
}

Následující příklad ukazuje deklarace obou předchozích výčtů:

var turnip = SomeRootVegetable.Turnip;

var spring = Seasons.Spring;
var startingOnEquinox = Seasons.Spring | Seasons.Autumn;
var theYear = Seasons.All;

Typy nullable

Proměnné libovolného typu mohou být deklarovány jako bez nullable _ nebo _nullable_. Proměnná s možnou hodnotou null může obsahovat další null hodnotu, která značí žádnou hodnotu. Typy hodnot s možnou hodnotou null (struktury nebo výčty) jsou reprezentovány hodnotou System.Nullable<T> . Odkazové typy s možnou hodnotou null i odkaz s možnou hodnotou Null jsou reprezentovány podkladovým odkazovým typem. Rozdíl je vyjádřen metadata čtená kompilátorem a některými knihovnami. Kompilátor zobrazí upozornění, pokud jsou odkazy s možnou hodnotou null odkazovány, aniž by nejprve kontroloval jejich hodnotu vůči null . Kompilátor také poskytuje upozornění, pokud jsou neuměnné odkazy přiřazeny hodnotě, která může být null . Následující příklad deklaruje _int s možnou_ hodnotou null , který ji inicializuje na null . Potom nastaví hodnotu na 5 . Předvede stejný koncept s řetězcem _s možnou hodnotou null**. Další informace najdete v tématu typy hodnot s možnou hodnotou null a odkazové typy s možnou hodnotou null.

int? optionalInt = default; 
optionalInt = 5;
string? optionalText = default;
optionalText = "Hello World.";

N-tice

Jazyk C# podporuje řazené kolekcečlenů , které poskytují stručnou syntaxi pro seskupení více datových prvků ve zjednodušené datové struktuře. Instanci řazené kolekce členů vytváříte deklarováním typů a názvů členů mezi a , jak ( ) je znázorněno v následujícím příkladu:

(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.

Řazené kolekce členů poskytují alternativu pro datovou strukturu s více členy bez použití stavebních bloků popsaných v dalším článku.