內建型別與字面值

小提示

剛開始開發軟體嗎? 先從 入門 教學開始。 它們會在你寫第一批程式時引入類型。

有其他語言的經驗嗎? C# 內建型別與 Java、C++ 及其他語言的型別對應非常緊密。 略讀 字面上的語法 和 型別推論 部分,了解 C# 專屬細節。

C# 提供了一組內建型別,你可以在任何程式中使用,無需額外引用。 這些類型涵蓋你最常用的資料:數字、真偽值、個別字元和文字。 若想完整地將 C# 關鍵字映射到 .NET 型別,請參見內建型別(C# 參考)。

數值類型

C# 內建整數、浮點數和十進位數的類型。 最常用的類型有 int、 double、 和 decimal:

int population = 67_000_000;
long distance = 384_400_000L;
short temperature = -40;
byte red = 255;

double pi = 3.141592653589793;
float gravity = 9.81f;
decimal price = 19.99m;

每個數字類型都有固定的大小和範圍。 int儲存 32 位元整數(約± 21 億)、long儲存 64 位元整數,而short和byte則儲存較小的值。 完整大小與範圍列表,請參見 積分數值類型 與 浮點數值類型。

double用於一般浮點數運算、float記憶體受限時,以及decimal需要精確小數精確度(例如財務計算)時。 把f後綴附加到float字面上,並把m後綴附加到decimal字面上。 若無後綴,編譯器會將帶有小數點的數字視為double。

無符號類型

每個有符號整數類型都有一個無符號對應類型,該類型僅儲存非負值,其範圍是其正值範圍的兩倍。

uint fileSize = 4_294_967_295;
ulong totalBytes = 18_446_744_073_709_551_615;
ushort port = 443;

當負值不適用於資料時,例如檔案大小或網路埠,你可能會使用無符號類型。 實務上,由於 .NET API 的預設值是有符號型別,許多應用程式即使在僅需正值時也使用 int 或 long。

原生大小整數

nint和 nuint 類型代表整數,其大小與平台的原生指標大小一致:在 32 位元平台上是 32 位元,在 64 位元平台上是 64 位元。

nint bufferSize = 1024;
nuint elementCount = 256;

你不太可能需要 nint ,也 nuint 不太可能在日常程式碼中出現。 它們存在於互操作情境及低階記憶體操作中,當平台指標大小匹配很重要時。 堅持使用 int ,或 long 除非你有特定理由使用原生尺寸的類型。 如需詳細資訊,請參閱 nint 和 nuint。

bool、char 和 string

除了數字之外,C# 還提供了另外三種常用的內建類型:

bool isValid = true;
char grade = 'A';
string greeting = "Hello, world!";
  • bool — 儲存 true 或 false。 在條件、迴圈和邏輯表達式中使用它。
  • char — 儲存一個 Unicode 字元(UTF-16 碼單元),以單引號包覆。
  • string — 儲存一連串字元,並以雙引號包圍。 弦是 不變的。 一旦你建立了字串,就無法更改它的內容。 看似修改字串的操作,實際上會產生新的字串。

字串是 C# 中最常用的類型之一。 關於字串操作的深入介紹,包括插值、原始字串字面量、搜尋、拆分與比較,請參閱 字串 章節。

字面語法

字面值是你直接寫在程式碼中的一個值。 編譯器會根據格式和你提供的後綴,為每個字面值指派一個型別。 C# 支援以下類型的文字:

  • 整數字面值 — 十進位(42)、十六進位(0x2A)、二進位(0b_0010_1010)。
  • 浮點數字面值 — double預設為3.14(),後綴為floatf(3.14f),且decimal使用m(3.14m)。
  • 字元字面值 — 單個字元置於單引號'A'內,包括跳脫序列'\n'。
  • 字串字面值 — 正則"hello"()、逐字(@"C:\path")、原始""" ... """()、插值($"value: {x}")。
  • 布林字面值 — true 和 false。
  • null文字 — 表示參考型別與可空值型別的值缺失。
  • default字面值 — 產生任何型別的預設值 (詳見default表達式)。

以下章節將詳細介紹最常見的字面形式。

整數字面值

int dec = 42;
int hex = 0x2A;
int bin = 0b_0010_1010;
long big = 1_000_000_000L;

十六進位用 0x 前綴,二進位用 0b 前綴。 附加 L 用於 long 、 U 用於 uint 或 UL 用於 ulong。

數字分隔符可以放在 _ 數字內的任何位置,這樣更容易閱讀。 常見模式包括十進位文字1_000_000_000中的千位分隔符、十六進位0xFF_FF中的位元組或字界限,以及二進位0b_0010_1010中的半位元界限。

浮點數文字

double d = 3.14;
float f = 3.14f;
decimal m = 3.14m;
double scientific = 1.5e6; // 1,500,000

若無後綴,帶有小數點的數值文字為 double。 為 float 附加 f,為 decimal 附加 m。 同時也支援科學記號1.5e6()。

字元與字串字面值

char newline = '\n';
char unicode = '\u0041'; // 'A'

string message = $"Found {dec} items";            // interpolated string
string path = @"C:\Users\docs\file.txt";        // verbatim string
string json = """
    { "name": "Alice", "age": 30 }
    """;                                           // raw string literal
string raw = $"""
    Found {dec} items in "{greeting}"
    """;                                           // raw + interpolated

字元文字使用單引號並支援跳脫序列(\n, \t, \u)。 字串文字使用雙引號。

請在字串前加上$ 進行插值。 當字串包含引號、斜線或嵌入的 JSON 或 XML 時,請使用原始字串字面值(以 """為界隔)而非逐字元跳脫。 原始字串文字也會與插值$"""()結合。

舊程式碼使用 @ (逐字串)來避免跳脫處理。 原始字串字面值比較容易讀寫,所以新程式碼會偏好用它們。

default 表達式

此default 表達式產生一個類型的預設值:0 是用於數值型別,false 是用於bool,以及 null 是用於參考型別。

int defaultInt = default;          // 0
bool defaultBool = default;        // false
string? defaultString = default;   // null

// Use default in a conditional:
var limit = (args.Length > 0) ? int.Parse(args[0]) : default(int);

這個default表達式在通用程式碼中最有用,因為你不知道具體的類型,也無法硬編碼像 或 0這樣的特定值null。 當編譯器能從上下文推斷出型別,或default型別不明顯時,寫入default(T)(不加型別參數)。 關於依類型分類的完整預設值清單,請參見 C# 型別的預設值。

隱式型別變數 var

關鍵字指示 var 編譯器從初始化器推斷出本地變數的型別:

var count = 10;              // compiler infers int
var name = "C#";             // compiler infers string
var items = new List<int>(); // compiler infers List<int>

// var requires an initializer — the compiler needs a value to infer the type.
// The following line wouldn't compile:
// var unknown;

變數仍然是強型別的;var 不會使它變成動態型別。 編譯器會在編譯時決定型別,並照常強制執行型別安全。 當字體從右側明顯可見時使用 var ,以減少視覺雜訊。 等到程式碼更清楚時再說出類型。 更多資訊請參見 隱式型別的局部變數。

目標類型 new 表達式

當你已經從上下文中知道目標型別,例如變數宣告或方法參數時,你可以省略表達式中的 new 型別名稱:

List<string> names = new() { "Alice", "Bob", "Charlie" };
Dictionary<string, int> scores = new()
{
    ["Alice"] = 95,
    ["Bob"] = 87
};

當類型名稱過長或出現在指派的左側時,目標類型 new 可以減少重複。 它適用於編譯器能判斷目標型別的任何地方,包括方法參數和回傳語句。 欲了解更多資訊,請參閱new操作員 — 目標型別。new

dynamic 類型

此 dynamic 型別可繞過編譯時型別檢查。 編譯器在執行時解析 dynamic 變數的操作。

dynamic value = 42;
Console.WriteLine(value.GetType()); // System.Int32

value = "Now I'm a string";
Console.WriteLine(value.GetType()); // System.String

// The compiler doesn't check operations on dynamic at compile time.
// Errors surface at run time instead.

當與 COM API、動態語言或在編譯時型別未知的反射重度情境互動時使用 dynamic 。 大多數應用程式碼避免 dynamic 使用,因為會失去編譯時的安全。 編譯器通常捕捉的錯誤會變成執行時例外。 欲了解更多資訊,請參閱 動態類型。

另請參閱