C# 基础语法
变量与类型、值类型与引用类型、字符串插值、模式匹配、控制流、nullable 引用类型、顶级语句
1. 变量与类型
1.1 内置类型
C# 提供丰富的内置类型,所有类型都继承自 System.Object:
| C# 类型 | .NET 类型 | 大小 | 范围 |
|---|---|---|---|
bool | System.Boolean | 1 字节 | true / false |
byte | System.Byte | 1 字节 | 0 ~ 255 |
sbyte | System.SByte | 1 字节 | -128 ~ 127 |
short | System.Int16 | 2 字节 | -32768 ~ 32767 |
int | System.Int32 | 4 字节 | -2³¹ ~ 2³¹-1 |
long | System.Int64 | 8 字节 | -2⁶³ ~ 2⁶³-1 |
float | System.Single | 4 字节 | ±1.5×10⁻⁴⁵ ~ ±3.4×10³⁸ |
double | System.Double | 8 字节 | ±5.0×10⁻³²⁴ ~ ±1.7×10³⁰⁸ |
decimal | System.Decimal | 16 字节 | ±1.0×10⁻²⁸ ~ ±7.9×10²⁸ |
char | System.Char | 2 字节 | U+0000 ~ U+FFFF |
string | System.String | 引用 | Unicode 字符序列 |
nint | System.IntPtr | 平台相关 | 本机整数 |
Int128 | System.Int128 | 16 字节 | .NET 8+ 128位整数 |
1.2 变量声明
// 显式类型
int age = 25;
string name = "张三";
double price = 99.99;
bool isActive = true;
// var 类型推断(编译期确定类型)
var count = 42; // int
var message = "Hello"; // string
var numbers = new[] { 1, 2, 3 }; // int[]
var dict = new Dictionary<string, int>(); // Dictionary<string, int>
// 常量
const double Pi = 3.14159265358979;
const string AppName = "FANDEX";
// C# 11 required 修饰符
public class Person
{
public required string Name { get; init; }
public required int Age { get; init; }
}
var person = new Person { Name = "李四", Age = 30 }; // 必须初始化
1.3 类型转换
// 隐式转换(安全,无数据丢失)
int num = 100;
long bigNum = num; // int → long
double d = num; // int → double
// 显式转换(可能丢失数据)
double pi = 3.14159;
int intPi = (int)pi; // 3,截断小数部分
// 使用 Convert 类
string str = "123";
int parsed = Convert.ToInt32(str);
double dbl = Convert.ToDouble("3.14");
// 使用 Parse / TryParse
int number = int.Parse("456");
if (int.TryParse("789", out int result))
{
Console.WriteLine($"解析成功: {result}");
}
// 安全的类型转换 (is / as)
object obj = "Hello";
if (obj is string s)
{
Console.WriteLine(s.Length); // 5
}
IAnimal? animal = dog as IAnimal; // 失败返回 null
2. 值类型与引用类型
2.1 核心区别
| 特性 | 值类型 | 引用类型 |
|---|---|---|
| 存储位置 | 栈(通常) | 堆 |
| 赋值行为 | 复制值 | 复制引用 |
| 默认值 | 0 / false | null |
| 继承 | 继承自 System.ValueType | 继承自 System.Object |
| 示例 | int, double, bool, struct, enum | class, string, array, delegate |
// 值类型 - 复制值
int a = 10;
int b = a; // b 得到 a 的副本
b = 20; // 不影响 a
Console.WriteLine(a); // 10
// 引用类型 - 复制引用
var list1 = new List<int> { 1, 2, 3 };
var list2 = list1; // list2 指向同一对象
list2.Add(4);
Console.WriteLine(list1.Count); // 4,list1 也受影响
// struct 是值类型
public struct Point
{
public double X { get; set; }
public double Y { get; set; }
public double Distance => Math.Sqrt(X * X + Y * Y);
}
// readonly struct(不可变值类型)
public readonly struct Money
{
public decimal Amount { get; init; }
public string Currency { get; init; }
}
2.2 装箱与拆箱
// 装箱:值类型 → 引用类型(分配堆内存)
int value = 42;
object boxed = value; // 装箱
// 拆箱:引用类型 → 值类型
int unboxed = (int)boxed; // 拆箱
// 避免频繁装箱,使用泛型
// 不好的做法
ArrayList list = new(); // 每次添加 int 都会装箱
list.Add(1);
// 好的做法
List<int> genericList = new(); // 无装箱
genericList.Add(1);
3. 字符串操作
3.1 字符串插值
var name = "世界";
var year = 2026;
// 基本插值
Console.WriteLine($"你好, {name}! 当前年份: {year}");
// 表达式插值
Console.WriteLine($"2 + 3 = {2 + 3}");
Console.WriteLine($"大写: {name.ToUpper()}");
Console.WriteLine($"时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
// C# 11 原始字符串字面量
var json = """
{
"name": "张三",
"age": 25,
"email": "zhangsan@example.com"
}
""";
// 插值原始字符串
var id = 1001;
var query = $"""
SELECT * FROM Users
WHERE Id = {id}
AND IsActive = 1
""";
3.2 常用字符串操作
string str = "Hello, C# World!";
// 查找
bool contains = str.Contains("C#"); // true
int index = str.IndexOf("World"); // 9
bool startsWith = str.StartsWith("Hello"); // true
// 截取与分割
string sub = str.Substring(7, 2); // "C#"
string[] parts = str.Split(' '); // ["Hello,", "C#", "World!"]
// 修改
string upper = str.ToUpper(); // "HELLO, C# WORLD!"
string trimmed = " hello ".Trim(); // "hello"
string replaced = str.Replace("C#", "F#"); // "Hello, F# World!"
// 字符串构建(高性能拼接)
var sb = new StringBuilder();
sb.AppendLine("第一行");
sb.AppendLine("第二行");
sb.AppendFormat("数字: {0:N2}", 1234.5678);
string result = sb.ToString();
4. Nullable 引用类型
C# 8.0 引入的可空引用类型是重要的类型安全增强,新项目默认启用:
#nullable enable
// 引用类型默认不可为 null
string name = "张三"; // OK
// string name2 = null; // 警告!
// 使用 ? 标记可为 null
string? nickname = null; // OK,无警告
// 访问前需要 null 检查
if (nickname is not null)
{
Console.WriteLine(nickname.Length); // 安全
}
// 空条件运算符
int? length = nickname?.Length; // null 如果 nickname 为 null
string upper = nickname?.ToUpper(); // null 如果 nickname 为 null
// 空合并运算符
string display = nickname ?? "匿名"; // null 时使用默认值
string display2 = nickname ??= "匿名"; // null 时赋值并返回
// 强制非空(慎用!)
string forced = nickname!; // 告诉编译器"我确定不为 null"
// 值类型可空
int? age = null; // Nullable<int>
bool hasValue = age.HasValue;
int value = age ?? 0; // 默认值
int value2 = age.GetValueOrDefault(18);
5. 控制流
5.1 条件语句
// if-else
int score = 85;
if (score >= 90)
Console.WriteLine("优秀");
else if (score >= 80)
Console.WriteLine("良好");
else if (score >= 60)
Console.WriteLine("及格");
else
Console.WriteLine("不及格");
// switch 语句
var day = DayOfWeek.Monday;
switch (day)
{
case DayOfWeek.Saturday:
case DayOfWeek.Sunday:
Console.WriteLine("周末");
break;
default:
Console.WriteLine("工作日");
break;
}
// switch 表达式(C# 8+)
string label = day switch
{
DayOfWeek.Saturday or DayOfWeek.Sunday => "周末",
_ => "工作日"
};
// 模式匹配 switch
object obj = 42;
string typeName = obj switch
{
int => "整数",
string => "字符串",
double => "浮点数",
null => "null",
_ => "其他"
};
5.2 循环语句
// for 循环
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
// foreach 循环
var fruits = new[] { "苹果", "香蕉", "橙子" };
foreach (var fruit in fruits)
{
Console.WriteLine(fruit);
}
// while 循环
int n = 10;
while (n > 0)
{
Console.WriteLine(n--);
}
// do-while 循环
string? input;
do
{
Console.Write("请输入 (q 退出): ");
input = Console.ReadLine();
} while (input != "q");
// 范围与索引(C# 8+)
var numbers = new[] { 10, 20, 30, 40, 50 };
int last = numbers[^1]; // 50(最后一个元素)
int secondLast = numbers[^2]; // 40
var slice = numbers[1..4]; // [20, 30, 40]
var firstThree = numbers[..3]; // [10, 20, 30]
6. 模式匹配
C# 的模式匹配功能持续增强,是现代 C# 最重要的特性之一:
// is 模式
object value = 42;
if (value is int num and > 0 and < 100)
{
Console.WriteLine($"0-100 之间的整数: {num}");
}
// 属性模式
public record Order(decimal Amount, string Status, Customer Customer);
string GetDiscount(Order order) => order switch
{
{ Status: "VIP", Amount: > 1000m } => "8折",
{ Status: "VIP" } => "9折",
{ Amount: > 500m } => "95折",
_ => "无折扣"
};
// 列表模式(C# 11)
int[] numbers = [1, 2, 3];
string label = numbers switch
{
[] => "空列表",
[single] => $"单个元素: {single}",
[first, .., last] => $"首: {first}, 尾: {last}",
[var a, var b, ..] => $"前两个: {a}, {b}"
};
// when 守卫
string Classify(int[] arr) => arr switch
{
[var a, .., var b] when a == b => "首尾相同",
[var a, .., var b] when a < b => "递增趋势",
_ => "其他"
};
7. 顶级语句与全局 Using
// GlobalUsings.cs - 全局 using 声明
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks;
global using System.IO;
// 隐式 using(csproj 中启用)
// <ImplicitUsings>enable</ImplicitUsings>
// 自动包含常用命名空间
// 文件范围命名空间(C# 10+)
namespace MyApp.Services;
public class UserService
{
// 无需缩进,整个文件都在该命名空间下
}
// 顶级语句中的异步支持
var data = await FetchDataAsync();
Console.WriteLine($"获取到 {data.Length} 条记录");
async Task<string[]> FetchDataAsync()
{
await Task.Delay(100);
return ["item1", "item2", "item3"];
}
8. 运算符速查
// 空合并
string? name = null;
string result = name ?? "默认"; // 默认
name ??= "赋值"; // null 时赋值
// 空条件
int? len = name?.Length;
// 类型模式
if (obj is string s) { /* 使用 s */ }
if (obj is not null) { /* 非 null */ }
// 范围运算符
var slice = array[1..^1]; // 跳过首尾
// with 表达式(record 类型)
var original = new Point(1, 2);
var modified = original with { X = 10 };
// 集合表达式(C# 12)
List<int> list = [1, 2, 3];
int[] arr = [..list, 4, 5]; // 展开 + 合并