第一次見到 C# 程序可能會有一些奇怪,程序中有一些
{
、}
、[]
這樣的符號。然而在逐漸深入瞭解 C# 語言的過程中,對這些符號和 C# 語言特有的其他符號會越來越熟悉,甚至會喜歡上它們。
本篇,我們繼續從演示一個簡單的程序示例開始,解釋該程序的功能和它的各組成部分。同時,介紹一些 C# 語言的基本語法。
簡單的 C# 程序示例
using System; /* 告訴編譯器這個程序使用 System 命名空間中的類型 */
namespace ConsoleApp /* 聲明一個新命名空間,名稱爲 ConsoleApp */
{
class Program /* 聲明一個新的類類型,名稱爲 Program */
{
/// <summary>
/// Main 是一個特殊方法,編譯器用它作爲程序的起始點
/// </summary>
static void Main()
{
int number; /* 聲明一個名爲 number 的變量 */
// 爲 number 賦值
number = 1;
// 輸出一行文字
Console.WriteLine("C# 語法基礎");
// 還是輸出一行文字
Console.WriteLine($"變量 number 的值是:{number}");
}
}
}
輸出
C# 語法基礎
變量 number 的值是:1
上面程序中每一行代碼的作用:
- 第 1 行
-
告訴編譯器這個程序使用
System
命名空間中的類型 - 第 3 行
-
聲明一個新命名空間,名稱爲
ConsoleApp
- 新命名空間從第 4 行的左大括號(
{
)開始一直延伸到第 24 行與之對應的右大括號(}
)結束 - 在這部分裏聲明的任何類型都是該命名空間的成員
- 新命名空間從第 4 行的左大括號(
- 第 5 行
-
聲明一個新的類類型,名稱爲
Program
- 任何在第 6 行和第 23 行的兩個大括號中間聲明的成員都是組成這個類的成員
- 第 10 行
-
聲明一個名稱爲
Main
的方法Main
是一個特殊方法,編譯器用它作爲程序的起始點
- 第 12 行
-
聲明一個名爲
number
的變量 - 第 15 行
-
爲
number
賦值 - 第 18 行和第 21 行
-
輸出一行文字
關於 C# 的語法,要介紹的內容有很多,我們從簡單的開始。
關鍵字
爲了使編譯器能夠解釋代碼,C# 中的某些單詞具有特殊地位和含義,它們稱爲關鍵字。關鍵字是預定義的保留標識符,對編譯器有特殊意義。在上面的代碼中,class
,static
和 void
均是關鍵字。
編譯器根據關鍵字識別代碼的結構與組織方式。由於編譯器對這些單詞有着嚴格的解釋,所以必須將關鍵字放在特定位置。如違反規則,編譯器會報錯。
C# 關鍵字列表
- | - | - |
---|---|---|
abstract | as | base |
break | byte | case |
char | checked | class |
continue | decimal | default |
do | double | else |
event | explicit | extern |
finally | fixed | float |
foreach | goto | if |
in | int | interface |
is | lock | long |
new | null | object |
out | override | params |
protected | public | readonly |
return | sbyte | sealed |
sizeof | stackalloc | static |
struct | switch | this |
true | try | typeof |
ulong | unchecked | unsafe |
using | using static | virtual |
volatile | while |
C# 上下文關鍵字列表
上下文關鍵字用於在代碼中提供特定含義,但它不是 C# 中的保留字。 一些上下文關鍵字(如 partial
和 where
)在兩個或多個上下文中有特殊含義。
- | - |
---|---|
add | alias |
async | await |
descending | dynamic |
from | get |
group | into |
let | nameof |
orderby | partial(類型) |
remove | select |
unmanaged(泛型類型約束) | value |
when(篩選條件) | where(泛型類型約束) |
yield |
標識符
標識符是一種字符串,開發者用來命名如變量、方法、參數和許多後面將要闡述的其他程序結構。有效標識符必須遵循以下規則:
- 不得將關鍵字用作標識符。
- 標識符必須以字母
a-z A-Z
或下劃線_
符號開頭。 - 標識符可以包含字母
a-z A-Z
,數字0-9
和下劃線_
符號。 - 標識符不得包含任何特殊字符(例如
!@ $ *.’[]
等),除了下劃線_
。 - 關鍵字附加“
@
”前綴可作爲標識符使用,例如:可命名局部變量@return
類似地,可命名方法@throw()
。
選擇簡潔而有意義的名稱,這使代碼更容易理解和重用。要選擇清晰(甚至是詳細)的名稱,尤其是在團隊中工作,或者開發要由別人使用的庫的時候。
標識符區分大小寫。例如,變量名 myVar
和 MyVar
是不同的標識符。舉個例子,在下面的代碼片段中,變量的聲明都是有效的,並聲明瞭不同的整型變量。但使用如此相似的名稱會使代碼更易出錯並更難調試,後續需要調試代碼的人會很不爽。
// 語法上有效,但非常混亂
int totalCycleCount;
int TotalCycleCount;
int TotalcycleCount;
標識符的大小寫規則
標識符有兩種基本的大小寫風格:
- PascalCasing
- camelCasing
PascalCasing 約定用於除參數名稱之外的所有標識符,將每個單詞的第一個字符大寫(包括超過兩個字母的首字母縮寫),如以下示例所示:
PropertyDescriptor
HtmlTag
(在 HtmlTag
中, 由於首字母縮寫詞 HTML
的長度超過兩個字母,所以僅首字母大寫。)
這裏有一種特殊情況,即遇到兩個字母的首字母縮略詞時,兩個字母都要大寫,如下面的標識符所示:
IOStream
camelCasing 約定僅用於參數名稱,將除第一個單詞之外的每個單詞的第一個字符大寫,如以下示例所示。 該示例還顯示,以 camelCasing 標識符開始的雙字母縮寫詞都是小寫的。
propertyDescriptor
ioStream
htmlTag
標識符命名規範
- 要更注重標識符的清晰而不是簡短。
- 不要在標識符名稱中使用單詞縮寫。
- 不要使用不被廣泛接受的首字母縮寫詞,即使被廣泛接受,非必要也不要用。
- 不要使用下劃線來區分單詞,也不要在標識符中的任何位置使用下劃線。
參考微軟官方“框架設計準則”,鏈接地址:https://docs.microsoft.com/zh-cn/dotnet/standard/design-guidelines/
類型定義
C# 所有代碼都出現在一個類型定義的內部,最常見的類型定義以關鍵字 class
開頭。
類型名稱(本例是 Program
)可以隨便取,但根據約定,它應當使用 PascalCase 風格。就本例來說,可選擇的名稱包括 Greetings
,HelloInigoMontoya
,Hello
或者簡單地稱爲 Program
。
class Program
{
// ...
}
Main
方法
Main
方法是 C# 應用程序的入口點。 (庫和服務不要求使用 Main
方法作爲入口點)。Main
方法是應用程序啓動後調用的第一個方法。
static void Main()
{
// ...
}
C# 要求 Main
方法返回 void
或 int
, 而且要麼無參,要麼接收一個字符串數組。
static int Main(string[] args)
{
// ...
return 0;
}
args
參數是用於接收命令行參數的字符串數組,用 System.Environment.CommandLine
獲取執行程序所用的完整命令。
Main
返回的 int
是狀態碼,標識程序執行是否成功。返回非零值通常意味着錯誤。
雖然 Main
方法聲明可進行某種程度的變化,但關鍵字 static
和方法名 Main
是始終都是需要的。以下是有效 Main
示例:
static void Main() { }
static int Main() { }
static void Main(string[] args) { }
static int Main(string[] args) { }
static async Task Main() { }
static async Task<int> Main() { }
static async Task Main(string[] args) { }
static async Task<int> Main(string[] args) { }
花括號、方法體和代碼塊
{
...
}
一般來說,所有的 C# 方法都使用花括號標記方法體的開始和結束。這是規定,不能省略。只有花括號({}
)能起這種作用,圓括號(()
)和方括號([]
)都不行。
花括號還可用於把方法中的多條語句合併爲一個單元或塊。
語句和語句分隔符
語句是描述一個類型或告訴程序去執行某個動作的一條源代碼指令,C# 通常用分號標識語句結束。每條語句都由代碼要執行的一個或多個行動構成。聲明變量、控制程序流程或調用方法,所有這些都是語句的例子。
例如,下面的代碼是一個由兩條簡單語句組成的序列。第一條語句定義了一個名稱爲 var1
的整型變量,並初始化它的值爲 5
。第二條語句將變量 var1
的值打印到屏幕窗口。
int var1 = 5;
System.Console.WriteLine("The value of var1 is {0}", var1);
語句可以是以分號結尾的單行代碼,也可以是語句塊中的一系列單行語句。 語句塊括在括號 {}
中,並且可以包含嵌套塊。 以下代碼演示了兩個單行語句示例和一個多行語句塊:
namespace ConsoleApp
{
class Program
{
static void Main()
{
// Declaration statement.
int counter;
// Assignment statement.
counter = 1;
// Error! This is an expression, not an expression statement.
// counter + 1;
// Declaration statements with initializers are functionally
// equivalent to declaration statement followed by assignment statement:
int[] radii = { 15, 32, 108, 74, 9 }; // Declare and initialize an array.
const double pi = 3.14159; // Declare and initialize constant.
// foreach statement block that contains multiple statements.
foreach (int radius in radii)
{
// Declaration statement with initializer.
double circumference = pi * (2 * radius);
// Expression statement (method invocation). A single-line
// statement can span multiple text lines because line breaks
// are treated as white space, which is ignored by the compiler.
System.Console.WriteLine("Radius of circle #{0} is {1}. Circumference = {2:N2}",
counter, radius, circumference);
// Expression statement (postfix increment).
counter++;
} // End of foreach statement block
} // End of Main method body.
} // End of SimpleStatements class.
}
由於換行與否不影響語句的分隔,所以可將多條語句放到同一行,C# 編譯器認爲這一行包含多條指令。例如,下面的代碼在同一行包含了兩條語句。
int var1 = 5;System.Console.WriteLine("The value of var1 is {0}", var1);
C# 還允許一條語句跨越多行。同樣地,C# 編譯器根據分號判斷語句結束位置。
System
.Console.
WriteLine
("The value of var1 is {0}",
var1);
空白
程序中的空白指的是沒有可視化輸出的字符,程序員在源代碼中使用的空白將被編譯器忽略。但使代碼更清晰易讀。空白字符包括:空格(Space)、製表符(Tab)、換行符、回車符。
例如,下面的代碼段會被編譯器完全相同地對待而不管它們表面上的區別。
// 推薦的格式
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
// 連在一起(不推薦的格式)
class Program {static void Main(string[] args){Console.WriteLine("Hello World!");}}
爲了增強可讀性,用空白對代碼進行縮進很有必要。寫代碼時要遵循制訂好的編碼標準和約定,以增強代碼的可讀性。
註釋
註釋,是代碼中的一些“說明性文字”。註釋本身不會參與程序的編譯和運行,僅僅供程序員閱讀。
註釋分爲:單行註釋、多行註釋、文檔註釋。
單行註釋的符號是 2 條斜線(請注意斜線的方向),2 條斜線右側的內容就是註釋,左側的代碼不會受影響。
多行註釋以“/*”開始,以“*/”結束,之間的內容就是註釋,可以包含多行。
文檔註釋寫在類、方法或屬性,它的符號是 3 條斜線“///”。
/// <summary>
/// XML(文檔)註釋
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// 單行註釋
var item = (Name: "eggplant", Price: 1.99m, perPackage: 3);
/* 多行註釋(可以寫一行,也可以寫多行) */
var date = DateTime.Now;
/*
多行註釋
註釋註釋
註釋
*/
Console.WriteLine($"On {date}, the price of {item.Name} was {item.Price:C2} per {item.perPackage} items.");
/*
* 這樣比較好看
* 嗯呢,好看
* 漂亮
*/
Console.WriteLine();
Console./*這是有多閒才這麼寫啊*/WriteLine();
}
編譯器會忽略所有的註釋,所以生成的程序集中看不到源代碼中的任何註釋。
總結
一門語言的語法是一套規則,用於管理語言中各有效語句組合在一起的方式。