宣言ステートメント
宣言ステートメントでは、新しいローカル変数、ローカル定数、またはローカル参照変数を宣言します。 ローカル変数を宣言するには、その型とその名前を指定します。 次の例に示すように、1 つのステートメントで同じ型の複数の変数を宣言できます。
string greeting;
int a, b, c;
List<double> xs;
宣言ステートメントでは、変数をその初期値で初期化することもできます。
string greeting = "Hello";
int a = 3, b = 2, c = a + b;
List<double> xs = new();
前の例では、変数の型を明示的に指定しています。 また、コンパイラに初期化式から変数の型を推論させることができます。 これを行うには、型の名前の代わりに var
キーワードを使用します。 詳細については、「暗黙的に型指定されたローカル変数」セクションを参照してください。
ローカル定数を宣言するには、次の例に示すように、const
キーワードを使用します。
const string Greeting = "Hello";
const double MinLimit = -10.0, MaxLimit = -MinLimit;
ローカル定数を宣言するときは、それを初期化する必要もあります。
ローカル参照変数の詳細については、「参照変数」セクションを参照してください。
暗黙的に型指定されたローカル変数
ローカル変数を宣言するときに、コンパイラに初期化式から変数の型を推論させることができます。 これを行うには、型の名前の代わりに var
キーワードを使用します。
var greeting = "Hello";
Console.WriteLine(greeting.GetType()); // output: System.String
var a = 32;
Console.WriteLine(a.GetType()); // output: System.Int32
var xs = new List<double>();
Console.WriteLine(xs.GetType()); // output: System.Collections.Generic.List`1[System.Double]
前の例に示すように、暗黙的に型指定されたローカル変数は厳密に型指定されます。
注意
有効な Null 許容認識コンテキスト で var
を使用し、初期化式の型が参照型である場合、コンパイラでは、初期化式の型が Null 許容でない場合でも、常に Null 許容 参照型を推論します。
var
は、コンストラクターの呼び出し式と共に使用するのが一般的です。 var
を使用すると、次の例に示すように、変数宣言およびオブジェクトのインスタンス化において型名を繰り返す必要がなくなります。
var xs = new List<int>();
代替として、ターゲット型の new
式を使用できます。
List<int> xs = new();
List<int>? ys = new();
匿名型を使う場合は、暗黙的に型指定されたローカル変数を使用する必要があります。 次の例は、匿名型を使用して顧客の名前と電話番号を保持するクエリ式を示しています。
var fromPhoenix = from cust in customers
where cust.City == "Phoenix"
select new { cust.Name, cust.Phone };
foreach (var customer in fromPhoenix)
{
Console.WriteLine($"Name={customer.Name}, Phone={customer.Phone}");
}
前の例では、fromPhoenix
変数の型を明示的に指定することはできません。 型は IEnumerable<T> ですが、この場合、T
は匿名型であり、その名前を指定することはできません。 そのため、var
を使用する必要があります。 同じ理由から、foreach
ステートメントで customer
反復変数を宣言するときは、var
を使用する必要があります。
暗黙的に型指定されたローカル変数の詳細については、「暗黙的に型指定されたローカル変数」を参照してください。
パターン マッチングでは、var
キーワードが var
パターンで使用されます。
参照変数
ローカル変数を宣言し、変数の型の前に ref
キーワードを追加する場合は、"参照変数" または ref
ローカルを宣言します。
ref int aliasOfvariable = ref variable;
参照変数は、別の変数を参照する変数であり、referent (リファレント) と呼ばれます。 つまり、参照変数は、そのリファレントの "別名" です。 参照変数に値を代入した場合、その値はリファレントに代入されます。 参照変数の値を読み取ると、リファレントの値が返されます。 次の例は、その動作を示します。
int a = 1;
ref int aliasOfa = ref a;
Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})"); // output: (a, aliasOfa) is (1, 1)
a = 2;
Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})"); // output: (a, aliasOfa) is (2, 2)
aliasOfa = 3;
Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})"); // output: (a, aliasOfa) is (3, 3)
次の例に示すように、ref
代入演算子 = ref
を使って、参照変数の参照先を変更します。
void Display(int[] s) => Console.WriteLine(string.Join(" ", s));
int[] xs = [0, 0, 0];
Display(xs);
ref int element = ref xs[0];
element = 1;
Display(xs);
element = ref xs[^1];
element = 3;
Display(xs);
// Output:
// 0 0 0
// 1 0 0
// 1 0 3
前の例では、element
参照変数は、最初の配列要素の別名として初期化されています。 次に、最後の配列要素を参照するように ref
再代入されています。
ref readonly
ローカル変数を定義できます。 ref readonly
変数に値を代入することはできません。 ただし、次の例に示すように、このような参照変数を ref
再代入することはできます。
int[] xs = [1, 2, 3];
ref readonly int element = ref xs[0];
// element = 100; error CS0131: The left-hand side of an assignment must be a variable, property or indexer
Console.WriteLine(element); // output: 1
element = ref xs[^1];
Console.WriteLine(element); // output: 3
次の例に示すように、参照戻り値を参照変数に代入できます。
using System;
public class NumberStore
{
private readonly int[] numbers = [1, 30, 7, 1557, 381, 63, 1027, 2550, 511, 1023];
public ref int GetReferenceToMax()
{
ref int max = ref numbers[0];
for (int i = 1; i < numbers.Length; i++)
{
if (numbers[i] > max)
{
max = ref numbers[i];
}
}
return ref max;
}
public override string ToString() => string.Join(" ", numbers);
}
public static class ReferenceReturnExample
{
public static void Run()
{
var store = new NumberStore();
Console.WriteLine($"Original sequence: {store.ToString()}");
ref int max = ref store.GetReferenceToMax();
max = 0;
Console.WriteLine($"Updated sequence: {store.ToString()}");
// Output:
// Original sequence: 1 30 7 1557 381 63 1027 2550 511 1023
// Updated sequence: 1 30 7 1557 381 63 1027 0 511 1023
}
}
前の例では、GetReferenceToMax
メソッドは returns-by-ref メソッドです。 最大値自体は返されませんが、最大値を保持する配列要素の別名である参照戻り値が返されます。 Run
メソッドは、参照戻り値を max
参照変数に代入します。 次に、max
に代入することで、store
インスタンスの内部ストレージを更新します。 ref readonly
メソッドを定義することもできます。 ref readonly
メソッドの呼び出し元は、その参照戻り値に値を代入することはできません。
foreach
ステートメントの反復変数は参照変数にすることができます。 詳細については、反復ステートメントに関する記事の「foreach
ステートメント」セクションをご覧ください。
パフォーマンスが重要なシナリオでは、参照変数と戻り値を使用すると、コストのかかる可能性のあるコピー操作を回避することでパフォーマンスが向上することがあります。
コンパイラは、参照変数がそのリファレントより長く存在しないように、またその有効期間全体にわたって有効なままであるようにします。 詳細については、C# 言語仕様の ref-safe-context に関するセクションを参照してください。
ref
フィールドの詳細については、「ref
構造体型」の「ref
フィールド」セクションを参照してください。
scoped ref
コンテキスト キーワード scoped
は、値の有効期間を制限します。 scoped
修飾子は、ref-safe-to-escape または safe-to-escape 有効期間をそれぞれ現在のメソッドに制限します。 実際には、scoped
修飾子を追加すると、コードによって変数の有効期間が延長されないというアサートが行われます。
パラメーターまたはローカル変数に scoped
を適用できます。 scoped
修飾子は、型が ref struct
の場合にパラメーターとローカルに適用されます。 それ以外の場合、scoped
修飾子は、ローカルの参照変数にのみ適用できます。 これには、ref
修飾子で宣言されたローカル変数と、in
、ref
、または out
修飾子で宣言されたパラメーターが含まれます。
scoped
修飾子は、型が ref struct
の場合は、struct
、out
パラメーター、および ref
パラメーターで宣言されたメソッドの this
に暗黙的に追加されます。
C# 言語仕様
詳細については、「C# 言語仕様」の次のセクションを参照してください。
scoped
修飾子の詳細については、「低レベル構造体の機能強化」の提案メモを参照してください。
関連項目
.NET