Předdefinované odkazové typy (referenční dokumentace jazyka C#)

Jazyk C# obsahuje mnoho předdefinovaných referenčních typů. Mají klíčová slova nebo operátory, které jsou synonymy pro typ v knihovně .NET.

Typ objektu

Typ object je alias pro System.Object v .NET. V systému sjednoceného typu jazyka C# všechny typy, předdefinované a uživatelem definované, odkazové typy a typy hodnot, dědí přímo nebo nepřímo z System.Object. Hodnoty libovolného typu můžete přiřadit proměnným typu object. Libovolnou object proměnnou lze přiřadit k její výchozí hodnotě pomocí literálu null. Když je proměnná typu hodnoty převedena na objekt, říká se, že je v rámečku. Když je proměnná typu object převedena na typ hodnoty, říká se, že je unboxed. Další informace naleznete v tématu Boxing and Unboxing.

Typ řetězce

Typ string představuje posloupnost nula nebo více znaků Unicode. string je alias pro System.String v .NET.

Ačkoli string je typ odkazu, operátory == rovnosti a != jsou definovány pro porovnání hodnot string objektů, nikoli odkazů. Rovnost na základě hodnot usnadňuje testování rovnosti řetězců intuitivněji. Příklad:

string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine(object.ReferenceEquals(a, b));

Předchozí příklad zobrazí hodnotu True a pak False, protože obsah řetězců je ekvivalentní, ale ab neodkazuje na stejnou instanci řetězce.

Operátor + zřetězí řetězce:

string a = "good " + "morning";

Předchozí kód vytvoří objekt řetězce, který obsahuje "dobré ráno".

Řetězce jsou neměnné – obsah objektu řetězce nelze po vytvoření objektu změnit. Například při psaní tohoto kódu kompilátor ve skutečnosti vytvoří nový objekt řetězce, který bude obsahovat novou sekvenci znaků a že nový objekt je přiřazen b. Paměť, pro b kterou byla přidělena (když obsahoval řetězec "h") je pak způsobilá pro uvolňování paměti.

string b = "h";
b += "ello";

Operátor []lze použít pro čtení přístupu k jednotlivým znakům řetězce. Platné hodnoty indexu začínají 0 a musí být menší než délka řetězce:

string str = "test";
char x = str[2];  // x = 's';

Podobně [] lze operátor použít také k iterování jednotlivých znaků v řetězci:

string str = "test";

for (int i = 0; i < str.Length; i++)
{
  Console.Write(str[i] + " ");
}
// Output: t e s t

Řetězcové literály

Řetězcové literály jsou typu string a dají se psát ve třech formách, nezpracovaných, uvozovaných a doslovných textech.

Nezpracované řetězcové literály jsou k dispozici od jazyka C# 11. Nezpracované řetězcové literály můžou obsahovat libovolný text bez nutnosti řídicích sekvencí. Nezpracované řetězcové literály můžou obsahovat prázdné znaky a nové řádky, vložené uvozovky a další speciální znaky. Nezpracované řetězcové literály jsou uzavřeny minimálně do tří dvojitých uvozovek ("""):

"""
This is a multi-line
    string literal with the second line indented.
"""

Můžete dokonce zahrnout posloupnost tří (nebo více) dvojitých uvozovek. Pokud text vyžaduje vloženou sekvenci uvozovek, začněte a ukončete nezpracovaný řetězcový literál dalšími uvozovkami podle potřeby:

"""""
This raw string literal has four """", count them: """" four!
embedded quote characters in a sequence. That's why it starts and ends
with five double quotes.

You could extend this example with as many embedded quotes as needed for your text.
"""""

Nezpracované řetězcové literály mají obvykle počáteční a koncové sekvence uvozovek na samostatných řádcích od vloženého textu. Víceřádkové řetězcové literály podporují řetězce, které jsou samy uvozovými řetězci:

var message = """
"This is a very important message."
""";
Console.WriteLine(message);
// output: "This is a very important message."

Když jsou počáteční a koncové uvozovky na samostatných řádcích, nové řádky za levou uvozovkou a před koncovou uvozovkou se do konečného obsahu nezahrnou. Posloupnost uvozovek určuje sloupec úplně vlevo pro řetězcový literál. Můžete odsadit nezpracovaný řetězcový literál tak, aby odpovídal celkovému formátu kódu:

var message = """
    "This is a very important message."
    """;
Console.WriteLine(message);
// output: "This is a very important message."
// The leftmost whitespace is not part of the raw string literal

Sloupce napravo od koncové sekvence uvozovek se zachovají. Toto chování umožňuje nezpracované řetězce pro formáty dat, jako jsou JSON, YAML nebo XML, jak je znázorněno v následujícím příkladu:

var json= """
    {
        "prop": 0
    }
    """;

Kompilátor vydá chybu, pokud se některý z textových řádků rozšíří nalevo od uzavírací sekvence uvozovek. Úvodní a uzavírací sekvence uvozovek můžou být na stejném řádku, takže řetězcový literál nezačíná ani nekončí znakem uvozovek:

var shortText = """He said "hello!" this morning.""";

Raw string literals with string interpolation to include quote characters and braces in the output string.

Řetězcové literály v uvozovkách ("):

"good morning"  // a string literal

Řetězcové literály mohou obsahovat libovolný literál znaků. Řídicí sekvence jsou zahrnuté. Následující příklad používá řídicí sekvenci \\ pro zpětné lomítko, \u0066 písmeno f a \n pro nový řádek.

string a = "\\\u0066\n F";
Console.WriteLine(a);
// Output:
// \f
//  F

Poznámka:

Řídicí kód \udddd (kde dddd je čtyřciferné číslo) představuje znak Unicode U+dddd. Rozpoznávají se také osmimístné řídicí kódy Unicode: \Udddddddd.

Doslovné řetězcové literály začínají @ a jsou také uzavřeny do dvojitých uvozovek. Příklad:

@"good morning"  // a string literal

Výhodou doslovných řetězců je, že řídicí sekvence se nezpracují , což usnadňuje zápis. Například následující text odpovídá plně kvalifikovanému názvu souboru systému Windows:

@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"

Pokud chcete do řetězce s uvozovkami zahrnout dvojitou uvozovku, poklikejte ji:

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.

Řetězcové literály UTF-8

Řetězce v .NET se ukládají pomocí kódování UTF-16. UTF-8 je standardem webových protokolů a dalších důležitých knihoven. Počínaje jazykem C# 11 můžete přidat příponu u8 do řetězcového literálu pro určení kódování UTF-8. Literály UTF-8 se ukládají jako ReadOnlySpan<byte> objekty. Přirozený typ řetězcového literálu UTF-8 je ReadOnlySpan<byte>. Použití řetězcového literálu UTF-8 vytvoří jasnější deklaraci než deklarování ekvivalentu System.ReadOnlySpan<T>, jak je znázorněno v následujícím kódu:

ReadOnlySpan<byte> AuthWithTrailingSpace = new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 };
ReadOnlySpan<byte> AuthStringLiteral = "AUTH "u8;

Pokud chcete uložit řetězcový literál UTF-8 jako pole, vyžaduje použití ReadOnlySpan<T>.ToArray() kopírování bajtů obsahujících literál do proměnlivého pole:

byte[] AuthStringLiteral = "AUTH "u8.ToArray();

Řetězcové literály UTF-8 nejsou časové konstanty kompilace; jsou to konstanty modulu runtime. Proto je nelze použít jako výchozí hodnotu volitelného parametru. Řetězcové literály UTF-8 nelze kombinovat s interpolací řetězců. Token a příponu $u8 nemůžete použít ve stejném řetězcovém výrazu.

Typ delegáta

Deklarace typu delegáta je podobná podpisu metody. Má návratovou hodnotu a libovolný počet parametrů libovolného typu:

public delegate void MessageDelegate(string message);
public delegate int AnotherDelegate(MyType m, long num);

V .NET System.Action a System.Func typy poskytují obecné definice pro mnoho běžných delegátů. Pravděpodobně nebudete muset definovat nové vlastní typy delegátů. Místo toho můžete vytvořit instanci zadaných obecných typů.

A delegate je typ odkazu, který lze použít k zapouzdření pojmenované nebo anonymní metody. Delegáti se podobají ukazatelům funkcí v jazyce C++; delegáti jsou však typově bezpečná a zabezpečená. Informace o aplikacích delegátů najdete v tématu Delegáti a obecné delegáty. Delegáti jsou základem událostí. Delegáta lze vytvořit tak, že ho přidružuje pojmenovanou nebo anonymní metodou.

Delegát musí být vytvořena pomocí metody nebo výrazu lambda, který má kompatibilní návratový typ a vstupní parametry. Další informace o stupni odchylky, která je povolena v podpisu metody, naleznete v tématu Variance in Delegates. Pro použití s anonymními metodami se delegát a kód, které se k němu mají přidružit, jsou deklarovány společně.

Kombinace nebo odebrání delegáta selže s výjimkou modulu runtime, pokud se typy delegátů zahrnuté v době běhu liší kvůli převodu varianty. Následující příklad ukazuje situaci, která selže:

Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
  
// Valid due to implicit reference conversion of
// objectAction to Action<string>, but may fail
// at run time.
Action<string> combination = stringAction + objectAction;

Delegáta se správným typem modulu runtime můžete vytvořit vytvořením nového objektu delegáta. Následující příklad ukazuje, jak se toto alternativní řešení může použít u předchozího příkladu.

Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
  
// Creates a new delegate instance with a runtime type of Action<string>.
Action<string> wrappedObjectAction = new Action<string>(objectAction);

// The two Action<string> delegate instances can now be combined.
Action<string> combination = stringAction + wrappedObjectAction;

Můžete deklarovat ukazatele na funkce, které používají podobnou syntaxi. Ukazatel funkce používá calli místo vytvoření instance typu delegáta a volání virtuální Invoke metody.

Dynamický typ

Typ dynamic označuje, že použití proměnné a odkazy na její členy obejít kontrolu typu kompilace v čase. Místo toho jsou tyto operace vyřešeny za běhu. Tento dynamic typ zjednodušuje přístup k rozhraním COM API, jako jsou rozhraní API služby Office Automation, k dynamickým rozhraním API, jako jsou knihovny IronPython, a k modelu DOM (Document Object Model) HTML.

Typ dynamic se chová jako typ object ve většině okolností. Konkrétně lze jakýkoli výraz, který není null, převést na dynamic typ. Typ dynamic se liší od object operací, které obsahují výrazy typu dynamic , nejsou překládány ani kontrolovány kompilátorem. Kompilátor zabalí informace o operaci dohromady a informace o této operaci se později použijí k vyhodnocení operace za běhu. V rámci procesu se proměnné typu dynamic kompilují do proměnných typu object. Proto typ dynamic existuje pouze v době kompilace, ne v době běhu.

Následující příklad kontrastuje proměnnou typu dynamic na proměnnou typu .object Pokud chcete ověřit typ každé proměnné v době kompilace, umístěte ukazatel myši na dyn příkazy nebo obj do WriteLine nich. Zkopírujte následující kód do editoru, kde je dostupná technologie IntelliSense. IntelliSense zobrazuje dynamické pro objekty a dynobjekty pro obj.

class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

Příkazy WriteLine zobrazují typy dyn runtime a obj. V tomto okamžiku mají oba stejný typ celé číslo. Vytvoří se následující výstup:

System.Int32
System.Int32

Pokud chcete zobrazit rozdíl mezi dyn a obj v době kompilace, přidejte mezi deklarace a WriteLine příkazy v předchozím příkladu následující dva řádky.

dyn = dyn + 3;
obj = obj + 3;

Byla hlášena chyba kompilátoru pro pokus o přidání celého čísla a objektu ve výrazu obj + 3. Není však hlášena žádná chyba .dyn + 3 Výraz, který obsahuje dyn , není kontrolován v době kompilace, protože typ dyn je dynamic.

Následující příklad používá dynamic v několika deklaracích. Metoda Main také kontrastuje kontrolu typů kompilace s kontrolou typů za běhu.

using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.ExampleMethod(10));
            Console.WriteLine(ec.ExampleMethod("value"));

            // The following line causes a compiler error because ExampleMethod
            // takes only one argument.
            //Console.WriteLine(ec.ExampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.ExampleMethod(10));

            // Because dynamic_ec is dynamic, the following call to ExampleMethod
            // with two arguments does not produce an error at compile time.
            // However, it does cause a run-time error.
            //Console.WriteLine(dynamic_ec.ExampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic _field;
        dynamic Prop { get; set; }

        public dynamic ExampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// Results:
// Local variable
// 2
// Local variable

specifikace jazyka C#

Další informace najdete v následujících částech specifikace jazyka C#:

Viz také