Deklarace příkazů
Příkaz deklarace deklaruje novou proměnnou a volitelně ji inicializuje. Všechny proměnné mají deklarovaný typ. Další informace o typech najdete v článku o systému typů .NET. Deklarace obvykle obsahuje typ a název proměnné. Může také obsahovat inicializaci: =
operátor následovaný výrazem. Typ může být nahrazen znakem var
. Deklarace nebo výraz může obsahovat ref
modifikátor, který deklaruje, že nová proměnná odkazuje na existující umístění úložiště.
Implicitně zadávané místní proměnné
Proměnné, které jsou deklarovány v oboru metody, můžou mít implicitní typ var
. Implicitně napsaná místní proměnná je silně zadáváná, jako kdybyste typ deklarovali sami, ale typ určuje kompilátor. Následující dvě deklarace a a
b
jsou funkčně ekvivalentní:
var a = 10; // Implicitly typed.
int b = 10; // Explicitly typed.
Důležité
Při var
použití s povolenými typy odkazů s možnou hodnotou null vždy znamená typ odkazu s možnou hodnotou null, i když typ výrazu není null. Analýza stavu null kompilátoru chrání před dereferencováním potenciální null
hodnoty. Pokud proměnná nikdy není přiřazena výrazu, který může být null, kompilátor nevygeneruje žádná upozornění. Pokud proměnnou přiřadíte výrazu, který může mít hodnotu null, musíte před dereferencováním otestovat, jestli není null, abyste se vyhnuli upozorněním.
Běžné použití klíčového var
slova je s konstruktorem vyvolání výrazů. Použití var
příkazu umožňuje neopakovat název typu v deklaraci proměnné a instanci objektu, jak ukazuje následující příklad:
var xs = new List<int>();
Počínaje jazykem C# 9.0 můžete jako alternativu new
použít cílový výraz :
List<int> xs = new();
List<int>? ys = new();
Při porovnávání vzorů var
se klíčové slovo používá ve vzoruvar
.
Následující příklad ukazuje dva výrazy dotazu. V prvním výrazu je použití parametru var
povolené, ale nevyžaduje se, protože typ výsledku dotazu lze explicitně uvést jako IEnumerable<string>
. Ve druhém výrazu však umožňuje, var
aby výsledkem byla kolekce anonymních typů a název tohoto typu není přístupný s výjimkou samotného kompilátoru. Použití nástroje var
eliminuje požadavek na vytvoření nové třídy pro výsledek. V příkladu foreach
2 musí být implicitně zadána také proměnná item
iterace.
// Example #1: var is optional when
// the select clause specifies a string
string[] words = { "apple", "strawberry", "grape", "peach", "banana" };
var wordQuery = from word in words
where word[0] == 'g'
select word;
// Because each element in the sequence is a string,
// not an anonymous type, var is optional here also.
foreach (string s in wordQuery)
{
Console.WriteLine(s);
}
// Example #2: var is required because
// the select clause specifies an anonymous type
var custQuery = from cust in customers
where cust.City == "Phoenix"
select new { cust.Name, cust.Phone };
// var must be used because each item
// in the sequence is an anonymous type
foreach (var item in custQuery)
{
Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);
}
Referenční místní hodnoty
Před typ proměnné přidáte ref
klíčové slovo, které deklaruje ref
místní. Místní ref
je proměnná, která odkazuje na jiné úložiště. Předpokládejme, že GetContactInformation
je metoda deklarována jako návrat odkazu:
public ref Person GetContactInformation(string fname, string lname)
Porovnejme tato dvě přiřazení:
Person p = contacts.GetContactInformation("Brandie", "Best");
ref Person p2 = ref contacts.GetContactInformation("Brandie", "Best");
Proměnná p
obsahuje kopii návratové hodnoty z GetContactInformation
. Jedná se o samostatné umístění úložiště od návratu ref
z GetContactInformation
. Pokud změníte libovolnou vlastnost objektu p
, změníte kopii objektu Person
.
Proměnná p2
odkazuje na umístění úložiště pro ref
návrat z GetContactInformation
. Je to stejné úložiště jako ref
vrácení z GetContactInformation
. Pokud změníte libovolnou vlastnost objektu p2
, změníte tuto jednu instanci objektu Person
.
K hodnotě můžete přistupovat odkazem stejným způsobem. V některých případech se při přístupu k hodnotě pomocí odkazu zvýší výkon tím, že se vyhnete potenciálně nákladné operaci kopírování. Následující příkaz například ukazuje, jak lze definovat místní hodnotu odkazu, která se používá k odkazování na hodnotu.
ref VeryLargeStruct reflocal = ref veryLargeStruct;
Klíčové ref
slovo se používá před deklaraci místní proměnné i před hodnotou v druhém příkladu. Nezahrnutí obou ref
klíčových slov do deklarace proměnné a přiřazení v obou příkladech má za následek chybu kompilátoru CS8172: "Nelze inicializovat proměnnou podle odkazu s hodnotou."
ref VeryLargeStruct reflocal = ref veryLargeStruct; // initialization
refLocal = ref anotherVeryLargeStruct; // reassigned, refLocal refers to different storage.
Místní proměnné odkazu musí být stále inicializovány, když jsou deklarovány.
Následující příklad definuje třídu, která ukládá pole celočíselných NumberStore
hodnot. Metoda FindNumber
vrátí odkazem první číslo, které je větší než nebo rovno číslu předaným jako argument. Pokud žádné číslo není větší nebo rovno argumentu, vrátí metoda číslo v indexu 0.
using System;
class NumberStore
{
int[] numbers = { 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 };
public ref int FindNumber(int target)
{
for (int ctr = 0; ctr < numbers.Length; ctr++)
{
if (numbers[ctr] >= target)
return ref numbers[ctr];
}
return ref numbers[0];
}
public override string ToString() => string.Join(" ", numbers);
}
Následující příklad volá metodu NumberStore.FindNumber
pro načtení první hodnoty, která je větší než nebo rovna 16. Volající pak zdvojnásobí hodnotu vrácenou metodou. Výstup z příkladu ukazuje změnu, která se odráží v hodnotě prvků NumberStore
pole instance.
var store = new NumberStore();
Console.WriteLine($"Original sequence: {store.ToString()}");
int number = 16;
ref var value = ref store.FindNumber(number);
value *= 2;
Console.WriteLine($"New sequence: {store.ToString()}");
// The example displays the following output:
// Original sequence: 1 3 7 15 31 63 127 255 511 1023
// New sequence: 1 3 7 15 62 63 127 255 511 1023
Bez podpory návratových hodnot odkazu se taková operace provede vrácením indexu elementu pole spolu s jeho hodnotou. Volající pak může použít tento index k úpravě hodnoty v samostatném volání metody. Volající však může také upravit index pro přístup a případně upravit jiné hodnoty pole.
Následující příklad ukazuje, jak je možné metodu FindNumber
přepsat tak, aby používala místní přiřazení odkazu:
using System;
class NumberStore
{
int[] numbers = { 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 };
public ref int FindNumber(int target)
{
ref int returnVal = ref numbers[0];
var ctr = numbers.Length - 1;
while ((ctr >= 0) && (numbers[ctr] >= target))
{
returnVal = ref numbers[ctr];
ctr--;
}
return ref returnVal;
}
public override string ToString() => string.Join(" ", numbers);
}
Tato druhá verze je efektivnější s delšími sekvencemi ve scénářích, kdy je hledané číslo blíže ke konci pole, protože pole je iterated od konce směrem k začátku, což způsobuje méně položek ke zkoumání.
Kompilátor vynucuje pravidla oboru u ref
proměnných: ref
místní hodnoty, ref
parametry a ref
pole v ref struct
typech. Pravidla zajišťují, že odkaz nepřežije objekt, na který odkazuje. Viz část věnovaná pravidlu vymezení rozsahu v článku věnovaném parametrům metody.
odkaz a jen pro čtení
Modifikátor readonly
lze použít u ref
místních proměnných a ref
polí. Modifikátor readonly
ovlivní výraz napravo. Projděte si následující ukázkové deklarace:
ref readonly int aConstant; // aConstant can't be value-reassigned.
readonly ref int Storage; // Storage can't be ref-reassigned.
readonly ref readonly int CantChange; // CantChange can't be value-reassigned or ref-reassigned.
- změna přiřazení hodnoty znamená, že hodnota proměnné je znovu přiřazena.
- Přiřazení odkazu znamená, že proměnná nyní odkazuje na jiný objekt.
Deklarace readonly ref
a readonly ref readonly
jsou platné pouze pro ref
pole v objektu ref struct
.
referenční informace s vymezeným oborem
Kontextové klíčové slovo scoped
omezuje životnost hodnoty. Modifikátor scoped
omezuje životnost ref-safe-to-escape nebo safe-to-escape na aktuální metodu. Přidání modifikátoru scoped
v podstatě tvrdí, že váš kód neprodlouží životnost proměnné.
Můžete použít scoped
pro parametr nebo místní proměnnou. Modifikátor scoped
může být použit pro parametry a místní hodnoty, pokud je typem ref struct
. V opačném scoped
případě lze modifikátor použít pouze u místních proměnných, které jsou typy odkazů. To zahrnuje místní proměnné deklarované pomocí modifikátoru ref
a parametry deklarované pomocí in
modifikátorů , ref
nebo out
.
Modifikátor scoped
je implicitně přidán do this
metod deklarovaných v struct
parametrech , out
parametry a ref
parametry, pokud je typem ref struct
.