Třída je základní stavební kámen objektově orientovaného programování (OOP).
Je to šablona, podle které se vytvářejí objekty (instance).

Třída definuje:

  • data, která objekt bude mít (tzv. členské proměnné nebo fields)
  • chování, tedy metody, které s těmito daty mohou pracovat

Každá třída si může udržovat svůj vnitřní stav (hodnoty vlastností, proměnných…) a je zodpovědná, aby se vždy nacházela ve validním stavu.

  • To znamená, že neobsahuje nesprávná data zadaná uživatelem a nesnaží se nad nimi dělat nějaké operace.

Objekt (instance) vzniká vyplněním šablony (třídy) konkrétními daty a následně existuje reálně v paměti počítače.

Ukázka třídy Car:

public class Car
{
    public string Brand;
    public int Year;
   
    public void Start()
    {
        Console.WriteLine("Auto nastartovalo.");
    }
}

Z této třídy lze vytvořit objekty (instance):

Car myCar = new Car()
{
    Brand = "Škoda",
    Year = 2021;
};
 
myCar.Start();

Definice tříd

Třídy se definují pomocí klíčového slova class a mohou obsahovat:

  • Členské proměnné (fields)
  • Konstruktory (constructors)
  • Vlastnosti (properties)
  • Metody (methods)
  • Události (events)
  • Vnořené typy (Nested types)
  • Finalizéry (finalizers)

U tříd a jejich obsahu lze specifikovat odkud k nim lze přistupovat pomocí modifikátorů přístupu.

Zastiňování členů (Member shadowing)

Pokud se v rodičovské i odvozené třídě nachází člen se stejným názvem. Vždy se použije člen, který je nejblíže v hierarchii k použitému typu.

public class A
{
   public void PrintText() { ... }
} 
 
public class B : A
{
   public void PrintText() { ... }
}

Velmi zhoršuje čitelnost kódu, proto kompilátor navrhuje použít klíčové slovo new v definici metody ve třídě B.

public class A
{
   public void PrintText() { ... }
} 
 
public class B : A
{
   public new void PrintText() { ... }
}

Životní cyklus tříd

  1. Instanciace – v běhu programu se vytvoří konkrétní objekt podle šablony třídy (pomocí new)
  2. Použití – volání metod, přístup k datům objektu
  3. Uvolnění z paměti – objekt přestane být používán, paměť se uvolní (v .NET prostřednictvím Garbage Collectoru)

Statický vs. instanční kontext

Třídy mohou být buďto instanční nebo statické v závislosti na účelu jejich existence. Více o kontextech lze najít zde: Statický vs. instanční kontext.

Obsah třídy

Členské proměnné (Fields)

Členské proměnné jsou proměnné deklarované přímo v těle třídy. Uchovávají data objektu.

public string Name;
private int _age;

Vlastnosti (Properties)

Vlastnosti slouží ke zpřístupnění interních dat objektu (fields) bezpečným způsobem. Mohou obsahovat logiku při čtení nebo zápisu hodnoty. Více o vlastnostech lze nalézt na stránce Vlastnosti.

public string Name { get; set; }

Metody (Methods)

Metody definují chování objektu. Může jít o běžné metody, přetížené metody, statické metody, virtuální nebo abstraktní metody atd. Více o metodách lze nalézt zde: Metody.

public void PrintName()
{
    Console.WriteLine(Name);
}

Konstruktory (Constructors)

Konstruktor je speciální metoda, která se volá při vytváření objektu. Slouží k inicializaci objektu (např. nastavení defaultních hodnot).

  • má stejný název jako třída
  • nemá návratový typ
  • může být přetížený (více verzí s různými parametry)
public class Person
{
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

Ukázka volání konstruktoru:

var person = new Person("Alice", 30);

Implicitní konstruktor

Pokud není napsán žádný konstruktor, tak kompilátor automaticky vytvoří výchozí konstruktor bez parametrů. Bez něj by například nebylo možné udělat toto:

var person = new Person();

Destruktory (Destructors)

Destruktor je speciální metoda, která se volá těsně před tím, než je objekt odstraněn z paměti (více o odstraňování z paměti zde: Správa paměti). V C# jsou destruktory nazývány jako finalizéry.

~Person()
{
    // Uvolnění unmanaged zdrojů
}

Pozor na finalizér!

  • běžně se nepoužívá
  • finalizér nelze volat ručně (není metoda)
  • negarantuje se, kdy se spustí (nebo zda vůbec)
  • finalizéry snižují výkon (objekty s finalizérem se musejí „dofinalizovat“ ve speciální fázi GC)

Typicky se používá při práci s unmanaged resources, např. soubory, handly, GDI objekty. Většinou se ale doporučuje místo finalizéru implementovat IDisposable (viz článek Disposable).

Kompletní ukázka

public class Person
{
    // Field
    private int _age;
 
    // Auto-property
    public string Name { get; set; }
 
    // Property s logikou
    public int Age
    {
        get => _age;
        set
        {
            if (value < 0)
                throw new ArgumentException("Věk nemůže být záporný.");
            _age = value;
        }
    }
 
    // Constructor
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
 
    // Method
    public void SayHello()
    {
        Console.WriteLine($"Ahoj, jmenuji se {Name} a je mi {Age} let.");
    }
 
    // Static Method
    public static void PrintGreeting()
    {
        Console.WriteLine("Zdraví vás třída Person!");
    }
 
    // Finalizer
    ~Person()
    {
        Console.WriteLine("Objekt Person bude odstraněn z paměti.");
    }
}

Použití:

var person = new Person("Alice", 30);
person.SayHello();
 
Person.PrintGreeting();

Partial třídy

Partial třídy rozdělit deklaraci jedné třídy do více souborů. To je užitečné zejména v případech, kdy část kódu generuje nástroj (např. Visual Studio pro návrh formulářů) a vývojář chce zachovat vlastní logiku odděleně, aby se nepřepsala.

Deklarace třídy jako partial říká kompilátoru, že definice této třídy může být rozdělena mezi více souborů. Při kompilaci jsou tyto části spojeny do jedné třídy.

Ukázka

Person.Part1.cs
public partial class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
Person.Part2.cs
public partial class Person
{
    public string GetFullName()
    {
        return $"{FirstName} {LastName}";
    }
}