宣告陳述式
宣告陳述式會宣告新的區域變數、區域常數或區域參考變數。 若要宣告區域變數,請指定其型別並提供其名稱。 您可以如下列範例所示,在一個陳述式中宣告多個相同型別的變數:
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
local:
ref int aliasOfvariable = ref variable;
參考變數是參考另一個變數的變數,稱為參照。 也就是說,參考變數是其參照的別名。 當您將值指派給參考變數時,便會將該值指派給參照。 當您讀取參考變數的值時,便會傳回參照的值。 下列範例示範了該行為:
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 安全內容一節。
如需 ref
欄位的相關資訊,請參閱ref
結構類型文章的 ref
欄位一節。
限定範圍 ref
內容關鍵字 scoped
會限制值的存留期。 scoped
修飾元會將 ref-safe-to-escape 或 safe-to-escape 存留期分別限制為目前方法。 實際上,新增 scoped
修飾元會判斷提示您的程式碼將不會延長變數的存留期。
您可以將 scoped
套用至參數或區域變數。 類型為 ref struct
時,scoped
修飾元可能會套用至參數和區域變數。 否則,scoped
修飾元只能套用至區域參考變數。 這包括使用 ref
修飾元所宣告的區域變數,以及使用 in
、ref
或 out
修飾元所宣告的參數。
類型為 ref struct
時,scoped
修飾元會隱含地新增至 struct
中所宣告方法內的 this
、out
參數和 ref
參數。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的下列幾節:
如需 scoped
修飾元的詳細資訊,請參閱低階結構改善提案注意事項。