常用特殊符号与关键字语法糖速查指南
1. 空值(Null)与可空类型处理
Type?(可空值类型 / Nullable Types)
说明:C# 中的基本值类型(如
int,bool,double,DateTime,struct等)默认是不允许为null的。在类型后面加上?,可以将其提升为“可空值类型”,使其能够赋予null值(本质上是Nullable<T>的语法糖)。代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 普通值类型:不能赋值 null,编译直接报错
// int age = null;
// 可空值类型:可以赋值 null(常用于数据库中的 Nullable 字段或未填项)
int? age = null;
DateTime? birthDate = null;
if (age.HasValue)
{
Console.WriteLine($"年龄是:{age.Value}");
}
else
{
Console.WriteLine("年龄未填写");
}
?. 与 ?[](Null 条件运算符)
说明:在访问对象的属性、方法或索引器之前先检查对象是否为
null。如果是null则直接返回null,不会抛出NullReferenceException异常。代码示例:
1
2
3
4
5
6
7
8
9
10// 传统写法
string name = null;
if (user != null)
{
name = user.Name;
}
// 语法糖写法
string name = user?.Name;
int? count = list?[0]?.Count;
??(Null 合并运算符)
说明:如果左侧不为
null则返回左侧的值;如果左侧为null则返回右侧的默认值(常用于兜底)。代码示例:
1
2
3
4
5// 如果 username 为 null,则使用 "默认游客"
string displayName = username ?? "默认游客";
// 配合可空值类型使用:如果 age 为 null,就取 18
int finalAge = age ?? 18;
??=(Null 合并赋值运算符)
说明:当且仅当左侧变量为
null时,才将右侧的值赋给它。代码示例:
1
2// 如果 list 为 null,就初始化一个新的 List;如果不为 null,保持原样
list ??= new List<string>();
!(Null 包容 / 警告抑制运算符)
说明:告诉编译器“我确定这里绝对不会是 null,不必报 null 警告”(仅影响编译期,运行时若真为 null 仍会报错,需谨慎使用)。
代码示例:
1
string text = GetNullableText()!; // 告诉编译器“不用担心,返回值绝对不是 null”
2. 类型检查与安全转换:is 与 as
这两个关键字都用于安全的类型转换或判断,主要区别如下:
| 关键字 | 主要作用 | 转换失败结果 | 使用场景 |
|---|---|---|---|
is |
检查对象是否匹配某种类型或模式 | 返回false |
逻辑判断(if条件) |
as |
尝试转换为指定引用类型或可空类型 | 返回null(不抛异常) |
需要直接获取转换后的对象 |
is 的用法(配合模式匹配)
- 代码示例:
1 | object obj = "Hello C#"; |
as 的用法
代码示例:
1
2
3
4
5
6
7
8
9object obj = "Hello C#";
// 强转成功返回实例,失败返回 null
string str = obj as string;
if (str != null)
{
Console.WriteLine(str.Length);
}
PS:在 C# 7.0 及以上版本中,优先推荐使用
if (obj is Type t)模式匹配,比as更加直观且安全。
3. using 的多重语法糖与用法
using 关键字在 C# 中不仅能用来引入命名空间,更核心的功能是管理资源释放(自动调用 Dispose )以及类型别名定义。
① using 声明(C# 8.0+ 简化语法)
说明:传统的
using (...) { }代码块需要一层嵌套的大括号。在 C# 8.0 及以上版本中,可以在变量声明前直接加using关键字,该变量会在当前作用域结束时自动释放,大幅减少了大括号嵌套。代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 传统写法:多层大括号,代码向右倾斜
using (var stream = new FileStream("test.txt", FileMode.Open))
{
using (var reader = new StreamReader(stream))
{
string content = reader.ReadToEnd();
} // reader 在这里被 Dispose
} // stream 在这里被 Dispose
// C# 8.0+ 语法糖:无需大括号,离开当前方法/作用域时自动按相反顺序释放
using var stream = new FileStream("test.txt", FileMode.Open);
using var reader = new StreamReader(stream);
string content = reader.ReadToEnd();
// 方法结束时,reader 和 stream 依次自动释放
② 全局 using 指令(Global Using,C# 10.0+)
说明:在任意
.cs文件顶部写上global using,该命名空间就会作用于整个项目里的所有文件,不再需要在每个.cs文件开头反复写一堆相同的using引用。代码示例:
1
2
3
4
5
6// 在项目的任意一个文件(如 GlobalUsings.cs)中集中声明:
global using System;
global using System.Collections.Generic;
global using System.Linq;
// 这样在项目的其他所有 .cs 文件中,都不需要再写上面这几行引用了,直接用!
③ using 别名(C# 12.0+ 强力增强)
说明:不仅可以给复杂的类名起简短别名,从 C# 12 开始,还可以给任何类型(包括元组、数组、指针等)起别名,非常适合用来简化长类型签名。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 1. 解决同名类冲突或简化长类型
using WinFormButton = System.Windows.Forms.Button;
// 2. C# 12+:给复杂元组起别名(相当于轻量级的 struct)
using Point3D = (int X, int Y, int Z);
class Program
{
void Test()
{
Point3D point = (10, 20, 30);
Console.WriteLine(point.X); // 直接访问成员
}
}
4. 常用前缀与后缀符号
$(字符串插值)
说明:用于简化字符串拼接,直接在字符串内通过
{}引用变量。代码示例:
1
2string name = "Tom";
string msg = $"Hello, {name}!"; // 替代 string.Format
@(逐字字符串 / 关键字转义)
说明:不仅可以用来禁用字符串转义字符,还可以将 C# 保留关键字强行作为变量名使用。
代码示例:
1
2
3
4
5// 1. 无需写路径的双反斜杠 \\
string path = @"C:\Users\Admin\Desktop";
// 2. 强行将 event 关键字作为变量名
string @event = "Notice";
_(弃元 / Discard)
说明:显式声明不关心的返回值或参数,避免定义无用变量。
代码示例:
1
2
3
4
5// 不需要 out 的第二个结果
bool success = int.TryParse("123", out _);
// 元组解构时忽略某个值
var (name, _) = GetUserInfo();
5. 其它高效关键字与符号
default(默认值表达)
说明:获取类型的默认值(引用类型为
null,数值型为0,布尔型为false)。代码示例:
1
2
3// C# 7.1+ 支持无类型默认值字面量
int number = default; // 0
string text = default; // null
nameof(表达式名称字符串化)
说明:将变量、类、属性或方法的名字转为字符串。在后续重构代码重命名时,编译器会自动更新该名称,避免硬编码字符串写错的问题。
代码示例:
1
2
3
4
5if (user == null)
{
// 输出 "user" 字符串,比直接硬编码 "user" 更稳健
throw new ArgumentNullException(nameof(user));
}
::(命名空间别名限定符)
说明:解决不同命名空间下类名冲突的问题。
代码示例:
1
2
3
4using MyAlias = System.IO;
// 使用 :: 明确指定别名下的类型
MyAlias::Path.GetExtension("file.txt");




