Novinky v jazyce C# 15

C# 15 obsahuje následující nové funkce. Vyzkoušejte tyto funkce pomocí nejnovější insiders verze Visual Studio 2026 nebo náhledové sady SDK .NET 11:

C# 15 je nejnovější verze C# Preview. Verze .NET 11 Preview podporují C# 15. Další informace najdete v tématu Správa verzí jazyka C#.

Nejnovější sadu .NET 11 Preview SDK si můžete stáhnout ze stránky pro stahování .NET. Můžete si také stáhnout visual studio 2026 insiders, které zahrnuje sadu .NET 11 Preview SDK.

Stránka Co je nového v jazyce C# přidá nové funkce, když jsou dostupné ve verzích Public Preview. Oddíl pracovní sady na stránce stavu funkcionality roslyn sleduje, kdy se nadcházející funkcionality sloučí do hlavní větve.

Všechny zásadní změny představené v C# 15 najdete v našem článku o zásadníchzměnách

Poznámka:

Zajímá nás vaše názory na tyto funkce. Pokud zjistíte problémy s některou z těchto nových funkcí, vytvořte v úložišti dotnet/roslynnový problém.

Argumenty výrazů kolekce

Argumenty můžete předat konstruktoru podkladové kolekce nebo metodě továrny pomocí with(...) elementu jako prvního prvku ve výrazu kolekce. Tato funkce umožňuje zadat kapacitu, porovnávače nebo jiné parametry konstruktoru přímo v syntaxi výrazu kolekce.

Následující příklad ukazuje, jak předat kapacitní argument konstruktoru List<T> a také porovnávače HashSet<T>:

string[] values = ["one", "two", "three"];

// Pass capacity argument to List<T> constructor
List<string> names = [with(capacity: values.Length * 2), .. values];

// Pass comparer argument to HashSet<T> constructor
HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"];
// set contains only one element because all strings are equal with OrdinalIgnoreCase

Další informace o argumentech výrazů kolekce najdete v referenčním článku jazyka o výrazech kolekce nebo specifikaci funkce. Informace o použití argumentů výrazů kolekce v inicializátorech kolekce naleznete v tématu Objekty a inicializátory kolekce.

Typy sjednocení

C# 15 zavádí typy sjednocení, které představují hodnotu, která může být jedním z několika typů případů. Deklarujte sjednocení s klíčovým slovem union :

public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);

public union Pet(Cat, Dog, Bird);

Unióny poskytují implicitní převody z každého typu dat a kompilátor zajišťuje, že výrazy jsou úplné pro všechny typy případů:

Pet pet = new Dog("Rex");

string name = pet switch
{
    Dog d => d.Name,
    Cat c => c.Name,
    Bird b => b.Name,
};

Běhové prostředí zahrnuje typy UnionAttribute a IUnion od verze .NET 11 Preview 5. Některé funkce ze specifikace návrhu ještě nejsou implementovány. Tyto funkce přicházejí v budoucích verzích Preview.

Další informace najdete v referenčních informacích k typům sjednocení jazyka nebo specifikaci funkce.

Uzavřené hierarchie

Počínaje jazykem C# 15 můžete modifikátor použít closed u třídy a deklarovat uzavřenou hierarchii. Z uzavřené třídy lze dědit pouze v rámci sestavení, ve kterém je deklarována, což v době kompilace pevně stanoví množinu přímých odvozených tříd:

public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;

Protože kompilátor zná každého přímého potomka, je výraz switch, který zpracovává každý z nich, úplný a nepotřebuje výchozí větev:

string Describe(GateState state) => state switch
{
    Closed => "closed",
    Open(var percent) => $"{percent}% open",
    // No warning: every direct descendant of 'GateState' is handled.
};

closed Modifikátor je kontextové klíčové slovo. Třída closed je implicitně abstract a nelze ji zkombinovat s sealed, static nebo explicitním modifikátorem abstract. Odvození není tranzitivní: nezavřený potomek uzavřené třídy lze stále odvozovat z jiných sestavení. Chcete-li rozšířit kontrolu vyčerpávajícnosti níže v hierarchii, označte také mezilehlé potomky closed.

Další informace najdete v vzorech uzavřených modifikátorů a uzavřených hierarchií v odkazu na jazyk nebo specifikaci funkce.

Nástroje pro indexaci rozšíření

Počínaje jazykem C# 15 můžete deklarovat indexery v extension bloku. Indexery rozšíření umožňují indexovat do příjemce, jako by byl indexer deklarován v typu příjemce. Vzhledem k tomu, že indexery jsou vždy členy instance, musí blok rozšíření, který deklaruje indexer, poskytnout pojmenovaný parametr příjemce.

Následující příklad na IEnumerable<int> deklaruje indexer pouze pro čtení, který vrací prvek na zadané pozici:

public static class SequenceIndexer
{
    extension(IEnumerable<int> sequence)
    {
        public int this[int index] => sequence.ElementAt(index);
    }
}

Indexujete ho do příjemce, jako kdyby byl indexer členem typu příjemce:

IEnumerable<int> numbers = Enumerable.Range(1, 10);
int third = numbers[2];

Další informace naleznete v tématu Deklarace rozšíření v referenční dokumentaci jazyka nebo specifikace funkce.

Označeno break a continue

Od jazyka C# 15 mohou příkazy break a continue pojmenovat návěští v nadřazené konstrukci. Pomocí popisku break ukončete uzavřenou smyčku nebo switch příkaz. Pomocí popisku continue spusťte další iteraci ohraničující smyčky.

Pojmenované break a continue nahrazují alternativní řešení, která byste jinak použili k řízení toku programu ve vnořených smyčkách, například logický příznak, který nastavíte ve vnitřní smyčce a poté kontrolujete na každé vnější úrovni, nebo goto, který přeskočí za smyčky. Pojmenování cílové smyčky přímo ve skokovém příkazu odstraňuje nutnost tohoto pomocného sledování a usnadňuje čtení zamýšleného toku řízení.

outer: for (int row = 0; row < grid.Height; row++)
{
    for (int column = 0; column < grid.Width; column++)
    {
        if (grid[row, column].IsBlocked)
        {
            continue outer;
        }

        if (grid[row, column].IsGoal)
        {
            break outer;
        }
    }
}

Popisek umístěte přímo na smyčku nebo příkaz switch, který označuje. Bez návěští si break a continue zachovávají své původní chování a cílí na nejvnitřnější použitelný příkaz.

Pravidlo stylu IDE0410 označuje logický příznak a goto vzory, které může nahradit popisovaný příkaz jump a zobrazuje příklady před a po jednotlivých.

Další informace najdete v tématu Příkazy skoku v referenčních informacích k jazyku nebo ve specifikaci funkce.

Bezpečnost paměti

C# 15 zahajuje víceverzovou iniciativu s cílem nově vymezit bezpečnost paměti v jazyce. Cílem je svázat unsafe kontext s operacemi, které ve skutečnosti přistupují k nespravované paměti, nikoli k existenci typů ukazatelů. Většina zranitelností souvisejících s bezpečností paměti pochází z těchto přístupových operací, takže je jazyk zvýrazňuje pro recenzenty a auditory.

V kompletním modelu označuje unsafe na členu tento člen jako requires-unsafe: povinnost auditu přechází na volajícího, který musí člena použít v kontextu unsafe. Sestavení se výslovně podřídí tomuto vynucování a kompilátor tuto volbu zaznamená pomocí atributu System.Runtime.CompilerServices.MemorySafetyRulesAttribute. Model také přidává kontextový klíčový výraz safe, který označuje členy extern a pole s explicitním rozložením jako bezpečné. Tato pravidla společně jasně vymezují hranice potenciálního narušení bezpečnosti paměti v celém programu.

Prvním krokem je odpočinek ukazatele. Při kompilaci s jazykovou preview verzí už následující operace nevyžadují unsafe kontext:

  • Deklarování typu ukazatele a převzetí adresy proměnné pomocí operátoru &
  • Příkaz fixed , který připne proměnnou.
  • Převod výrazu stackalloc na ukazatel
  • Operátor sizeof použitý na libovolný nespravovaný typ.

Následující příklad vytvoří a připne ukazatel bez unsafe kontextu:

int number = 42;
int* pointer = &number;

int[] numbers = [10, 20, 30];
fixed (int* first = numbers)
{
    // Dereferencing the pointer still requires an unsafe context.
}

Operace, které přistupují k paměti, na niž ukazuje ukazatel, jako je dereference ukazatele (*p), přístup ke členu přes ukazatel (p->member), přístup k prvku přes ukazatel (p[i]) a volání funkčního ukazatele, stále vyžadují kontext unsafe.

C# 15 také přidá unsafe výraz, unsafe(expression)který vytvoří nebezpečný kontext pro jeden výraz. Je to užitečné tam, kde blok unsafe nemůže syntakticky vystupovat, například v inicializátoru pole, v inicializátoru konstruktoru nebo ve filtru catch:

class Header
{
    // A field initializer can't contain an unsafe block, but it can contain an unsafe expression.
    static readonly int Signature = unsafe(ReadSignature());

    static unsafe int ReadSignature()
    {
        int rawValue = 0x1234;
        int* pointer = &rawValue;
        return *pointer;
    }
}

Stejně jako ostatní součásti náhledu funkcí bezpečnosti paměti vyžadují výrazy unsafe jazykovou verzi preview a volbu kompilátoru AllowUnsafeBlocks.

Kompilátor také rozpozná safe kontextové klíčové slovo jako modifikátor u extern členů a polí explicitního rozložení. Model požadovaného člena a souhlas sestavení s aktualizovanými pravidly zabezpečení paměti však ještě nejsou k dispozici, takže safeunsafe momentálně nemají žádný vliv na volající.

Další informace naleznete v tématu Nebezpečný kód, typy ukazatelů a ukazatele funkce v odkazu na jazyk nebo specifikaci funkce.

Viz také