# 一.c# 基础阶段
## 1.程序结构
```c#
using System; // 引入命名空间
namespace HelloWorld // 命名空间声明
{
class Program // 类声明
{
static void Main(string[] args) // Main方法,程序入口点
{
Console.WriteLine("Hello, World!"); // 语句
}
}
}
```
## 2.关键字
C# 关键字是语言中具有特殊含义的保留字,不能用作标识符(如变量名、类名等)
**1). 访问修饰符**
| 关键字 | 描述 |
| ------------------ | ---------------------------- |
| public | 访问不受限制 |
| private | 只能在当前类中访问 |
| protected | 只能在当前类或派生类中访问 |
| internal | 只能在当前程序集中访问 |
| protected internal | 在当前程序集或派生类中可访问 |
| private protected | 在当前程序集的派生类中可访问 |
| file | 仅在当前文件中可访问 |
**2). 类型定义**
|关键字 |描述|
|-|-|
|class| 定义类|
|struct| 定义结构|
|interface |定义接口|
|enum| 定义枚举|
|delegate |定义委托|
|record |定义记录类型(新特性)|
**3). 基本数据类型**
|关键字 |描述|
|-|-|
|bool |布尔值(true/false)|
|byte, sbyte| 8位整数|
|short, ushort |16位整数|
|int, uint |32位整数|
|long, ulong| 64位整数|
|float |32位浮点数|
|double |64位浮点数|
|decimal |128位十进制数|
|char| Unicode字符|
|string |字符串|
|object |所有类型的基类|
|dynamic| 动态类型|
**4).流程控制**
|关键字 |描述|
|-|-|
|if, else |条件语句|
|switch, case, default| 多分支选择|
|for, foreach |循环结构|
|while, do |循环结构|
|break |跳出循环或switch|
|continue |跳过当前循环迭代|
|goto |跳转到标签(不推荐)|
|return |从方法返回值|
**5).方法相关**
|关键字| 描述|
|-|-|
|void |表示方法不返回值|
|ref| 按引用传递参数|
|out| 输出参数|
|params |可变数量参数|
|async| 异步方法|
|await |等待异步操作完成|
**6).类成员修饰符**
|关键字| 描述|
|-|-|
|static |静态成员|
|const| 常量|
|readonly |只读字段|
|new |创建对象或隐藏基类成员|
|this |当前实例引用|
|base |基类访问|
|virtual| 可重写的方法|
|override |重写基类方法|
|abstract| 抽象类或方法|
|sealed |密封类或方法|
|partial |分部类/方法|
**7).异常处理**
|关键字| 描述|
|-|-|
|try |尝试执行代码块|
|catch| 捕获异常|
|finally |无论是否异常都会执行|
|throw| 抛出异常|
**8).命名空间和程序集**
|关键字 |描述|
|-|-|
|namespace |定义命名空间|
|using |引入命名空间或创建别名|
**9).泛型**
| 关键字 | 描述 |
| ------- | ---------------- |
| where | 泛型类型约束 |
| default | 获取类型的默认值 |
**10).类型操作**
|关键字 |描述|
|-|-|
|is |类型检查|
|as |安全类型转换|
|sizeof |获取类型大小|
|typeof |获取类型信息|
|nameof |获取变量、类型或成员的名称|
**11).上下文关键字**
| 关键字 | 描述 |
| ----------- | ---------------------------- |
| add, remove | 事件访问器 |
| get, set | 属性访问器 |
| init | 仅初始化属性设置器 |
| value | 属性设置器中的隐式参数 |
| global | 全局命名空间别名 |
| when | catch或switch case的筛选条件 |
| with | 用于记录类型的非破坏性修改 |
**12).不安全代码**
|关键字 |描述|
|-|-|
|unsafe |不安全代码块|
|fixed |固定指针|
|stackalloc |栈上分配内存|
|volatile |易变字段|
**13).运算符重载**
|关键字 |描述|
|-|-|
|operator |重载运算符|
|checked, unchecked |控制算术溢出检查|
**14).其他**
| 关键字 | 描述 |
| ------ | ------------ |
| var | 隐式类型变量 |
| yield | 迭代器生成 |
## 3.数据类型和转换
### 3.1 值类型
**整数类型**
| 类型 | 关键字 | 大小 | 取值范围/描述 | 默认值 | 示例 |
| ------------ | ------ | ---- | ------------------------------- | ------ | ------------------- |
| 有符号字节 | sbyte | 8位 | -128 到 127 | 0 | sbyte a = -100; |
| 无符号字节 | byte | 8位 | 0 到 255 | 0 | byte b = 200; |
| 有符号短整型 | short | 16位 | -32,768 到 32,767 | | 0 short c = -20000; |
| 无符号短整型 | ushort | 16位 | 0 到 65,535 | 0 | ushort d = 60000; |
| 有符号整型 | int | 32位 | -2,147,483,648 到 2,147,483,647 | 0 | int e = -1000000; |
| 无符号整型 | uint | 32位 | 0 到 4,294,967,295 | 0 | uint f = 4000000; |
| 有符号长整型 | long | 64位 | -9.2×10¹⁸ 到 9.2×10¹⁸ | 0L | long g = -5L; |
| 无符号长整型 | ulong | 64位 | 0 到 1.8×10¹⁹ | 0UL | ulong h = 10UL; |
**浮点类型**
|类型 |关键字 |大小 |精度/范围 |默认值 |示例|
|-|-|-|-|-|-|
|单精度浮点 |float |32位| 7位精度,±1.5×10⁻⁴⁵到±3.4×10³⁸| 0.0F| float i = 3.14F;|
|双精度浮点 |double |64位 |15-16位精度,±5.0 × 10⁻³²⁴ 到 ±1.7 × 10³⁰⁸| 0.0D |double j = 3.14159;|
|十进制数 |decimal |128位 |28-29位精度,±1.0 × 10⁻²⁸ 到 7.9 × 10²⁸ |0.0M |decimal k = 123.456M;|
**其他值类型**
|类型 |关键字 |大小 |描述 |默认值| 示例|
|-|-|-|-|-|-|
|布尔型 |bool |8位| true 或 false| false |bool m = true;|
|字符型 |char |16位 |Unicode字符 (U+0000到U+FFFF) |'\0' |char l = 'A';|
**复合值类型**
```c#
// 结构体示例
public struct Point
{
public int X;
public int Y;
}
// 枚举示例
public enum Color : byte // 可指定基础类型
{
Red = 1,
Green = 2,
Blue = 3
}
// 元组示例
var tuple = (1, "text"); // ValueTuple<int, string>
```
### 3.2 引用类型
内置引用类型
|类型 |关键字| 描述 |默认值 |示例|
|-|-|-|-|-|
|字符串 |string |Unicode字符序列 |null |string s = "Hello";|
|对象 |object |所有类型的基类| null |object o = new();|
|动态类型 |dynamic |运行时类型检查 |null |dynamic d = 10;|
复合引用类型
```c#
// 类示例
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
// 接口示例
public interface IDrawable
{
void Draw();
}
// 数组示例
int[] numbers = { 1, 2, 3 }; // 一维数组
int[,] matrix = new int[2, 3]; // 二维数组
int[][] jagged = new int[3][]; // 交错数组
// 委托示例
public delegate void MyDelegate(string msg);
```
记录类型
```c#
// 记录类 (不可变引用类型)
public record Product(string Name, decimal Price);
// 记录结构 (不可变值类型)
public readonly record struct Point(int X, int Y);
```
### 3.3 特殊类型
可为空值类型
```c#
int? nullableInt = null; // Nullable<int>
double? nullableDouble = 3.14; // Nullable<double>
bool? nullableBool = null; // Nullable<bool>
// 安全访问
int value = nullableInt ?? -1; // 如果null则返回-1
```
指针类型
```c#
unsafe
{
int value = 10;
int* pointer = &value; // 获取地址
// 指针运算
int* p = stackalloc int[10]; // 栈上分配
p[0] = 1;
// 固定托管对象
int[] array = { 1, 2, 3 };
fixed (int* ptr = array)
{
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(*(ptr + i));
}
}
}
```
其他特殊类型
| 类型/概念 | 描述 | 示例 |
| ---------- | ---------------- | ---------------- |
| void | 表示无返回值 | void Method() |
| var | 隐式类型推断 | var x = 10; |
| nint/nuint | 平台相关整数大小 | nint size = 100; |
### 3.4 类型转换
隐式转换 (自动)
```c#
int i = 10;
long l = i; // 小范围转大范围
```
显式转换 (强制)
```c#
double d = 3.14;
int i = (int)d; // 大范围转小范围
```
方法转换
```c#
// Parse/TryParse
int num = int.Parse("123");
bool success = int.TryParse("abc", out int result);
// Convert类
decimal dec = Convert.ToDecimal(3.14);
```
类型检查与转换
```c#
object obj = "Hello";
// is 检查
if (obj is string) { /*...*/ }
// as 安全转换
string str = obj as string;
if (str != null) { /*...*/ }
// 模式匹配 (C# 7+)
if (obj is string s) { /* 使用s */ }
```
## 4.变量
**4.1 变量基础概念**
变量定义
- 变量是存储数据的命名内存位置
- 必须先声明后使用
- 包含:变量名、数据类型和值
变量声明语法
```c#
数据类型 变量名; // 声明
数据类型 变量名 = 初始值; // 声明并初始化
```
**4.2 变量类型分类**
按数据类型分类
| 类型 | 示例 | 说明 |
| ------------ | -------------------- | -------------------------- |
| 值类型变量 | int age = 25; | 直接存储数据 |
| 引用类型变量 | string name = "Tom"; | 存储数据引用 |
| 指针类型变量 | int\* ptr; | 存储内存地址(unsafe上下文) |
按作用域分类
| 类型 | 声明位置 | 生命周期 |
| -------- | ---------------- | ------------------ |
| 局部变量 | 方法/代码块内 | 所在代码块执行期间 |
| 字段变量 | 类/结构体内 | 所属对象存在期间 |
| 静态变量 | 类中用static声明 | 程序运行期间 |
| 参数变量 | 方法参数列表 | 方法执行期间 |
**4.3 变量/常量声明**
基本变量声明
```c#
int count; // 声明未初始化
double price = 19.99; // 声明并初始化
char grade = 'A'; // 字符类型
bool isCompleted = false; // 布尔类型
```
类型推断(var)
```c#
var message = "Hello"; // 编译为string
var number = 42; // 编译为int
var list = new List<int>(); // 编译为List<int>
// var必须初始化,不能用于字段声明
// var不能用于方法参数和返回类型
```
常量声明
```c#
const double PI = 3.14159;
const int MaxUsers = 100;
// 常量必须在声明时初始化
// 常量默认为静态(static)
```
元组变量
```c#
// 命名元组
var person = (Name: "Alice", Age: 25);
Console.WriteLine(person.Name);
// 解构元组
(string name, int age) = person;
```
**4.4 变量作用域规则**
局部变量作用域
```c#
void Method()
{
int x = 10; // 作用域开始
if (true)
{
int y = 20; // 仅在此块内有效
x = 30; // 可以访问外部变量
}
// y = 40; // 错误!y不可访问
} // 作用域结束,x被销毁
```
字段变量作用域
```c#
class MyClass
{
private int _field; // 类级作用域
void Method()
{
_field = 10; // 可在类内任何方法访问
}
}
```
变量隐藏
```c#
int x = 10;
if (true)
{
int x = 20; // 隐藏外部x
Console.WriteLine(x); // 20
}
Console.WriteLine(x); // 10
```
**4.5 特殊变量类型**
可为空变量
```c#
int? nullableInt = null; // Nullable<int>
double? price = null;
// 安全访问
int value = nullableInt ?? -1; // null合并运算符
```
固定大小缓冲区
```c#
unsafe struct FixedBuffer
{
public fixed char buffer[128]; // 固定大小数组
}
```
范围变量
> 范围变量(Range Variable)是LINQ查询表达式中的特殊变量,它表示数据源中的单个元素。范围变量是LINQ查询中的"临时代表",代表数据集合中的单个元素,只在当前查询表达式中有效,类似于foreach循环中的迭代变量。
```c#
var query = from num in numbers
where num > 5
select num; // num是范围变量
```
**4.6 变量命名规范**
1. 常规变量:camelCase (totalCount, userName)
2. 私有字段:\_camelCase (\_instanceCount, \_isInitialized)
3. 常量:PascalCase (MAX_SIZE, DEFAULT_TIMEOUT)
4. 布尔变量:以is/can/has开头 (isActive, hasPermission)
## 5.运算符和表达式
### 5.1 运算符
算术运算符
|运算符| 描述 |示例 |结果|
|-|-|-|-|
|+ |加法 |5 + 3| 8|
|- |减法| 10 - 4| 6|
|_| 乘法 |3 _ 4| 12|
|/ |除法| 10 / 3 |3|
|% |取模 |10 % 3 |1|
|++ |自增 |a++| a+1|
|-- |自减| a--| a-1|
关系运算符
|运算符| 描述| 示例 |结果|
|-|-|-|-|
|== |等于 |5 == 5 |true|
|!= |不等于| 5 != 3 |true|
|> |大于 |5 > 3| true|
|< |小于 |5 < 3 |false|
|>= |大于等于 |5 >= 5| true|
|<= |小于等于| 5 <= 3 |false|
逻辑运算符

位运算符

赋值运算符
|运算符 |示例 |等价形式|
|-|-|-|
|= |a = 5 | |
|+= |a += 3 |a = a + 3|
|-= |a -= 2 |a = a - 2|
| \* = |a \*= 4 |a = a \* 4|
|/= |a /= 2| a = a / 2|
|%= |a %= 3 |a = a % 3|
特殊运算符
|运算符| 描述 |示例|
|-|-|-
|?: |三元条件运算符 |x > 0 ? 1 : -1|
|?? |null合并运算符| name ?? "匿名"|
|?. |null条件运算符 |person?.Name|
|is |类型检查 |obj is string|
|as |安全类型转换 |obj as string|
|sizeof |获取类型大小| sizeof(int)|
|typeof |获取类型对象 |typeof(string)|
### 5.2 表达式
基本表达式
```c#
42 // 字面量表达式
a // 变量表达式
a + b // 算术表达式
a > b // 关系表达式
```
复合表达式
```c#
(a + b) * c // 组合算术表达式
(a > b) && (c < d) // 组合逻辑表达式
```
Lambda表达式
```c#
x => x * x // 单参数Lambda
() => Console.WriteLine("Hello") // 无参数Lambda
```
查询表达式
```c#
from n in numbers
where n > 5
select n // LINQ查询表达式
```
### 5.3 运算符优先级
(从高到低)1.成员访问 .、方法调用 ()、数组索引 [] 2.一元运算符 +、-、!、~、++、--、(类型) 3.乘除 \*、/、% 4.加减 +、- 5.移位 <<、>> 6.关系 <、>、<=、>=、is、as 7.相等 ==、!= 8.位与 & 9.位异或 ^ 10.位或 | 11.逻辑与 && 12.逻辑或 ||
13.null合并 ?? 14.三元条件 ?: 15.赋值 =、+=、-= 等
### 5.4 实用技巧
1.用括号明确优先级:(a + b) _ c 比 a + b _ c 更清晰
2.null检查简化:
```c#
// 传统方式
if (obj != null) { var name = obj.Name; }
// 使用?.运算符
var name = obj?.Name;
```
3.类型转换最佳实践:
```c#
// 安全转换(推荐)
string s = obj as string;
if (s != null) { ... }
// 强制转换(确定类型时使用)
string s = (string)obj;
```
4.模式匹配(C# 7.0+):
```c#
if (obj is string str) {
Console.WriteLine(str.Length);
}
```
5.范围运算符(C# 8.0+):
```c#
int[] arr = {1, 2, 3, 4, 5};
var sub = arr[1..4]; // 获取索引1-3 [2,3,4]
```
### 5.5 注意事项
1.整数除法会截断小数部分:5 / 2 = 2
2.++a(前缀)和 a++(后缀)有区别:
```c#
int a = 1;
int b = a++; // b=1, a=2
int c = ++a; // c=3, a=3
```
3.浮点数比较应使用容差而非直接==:
```c#
// 不推荐
if (d1 == d2) {...}
// 推荐
if (Math.Abs(d1 - d2) < 0.0001) {...}
```
4.运算符重载示例:
```c#
public class Program
{
public static void Main(string[] args)
{
Vector2D v1 = new Vector2D(1, 2);
Vector2D v2 = new Vector2D(3, 4);
var n = (v1 + v2);
Console.WriteLine($"new x:{n.X},new y:{n.Y}");
}
}
public class Vector2D
{
public double X { get; set; }
public double Y { get; set; }
public Vector2D(double x, double y)
{
X = x;
Y = y;
}
public static Vector2D operator +(Vector2D a, Vector2D b)
{
return new Vector2D(a.X + b.X, a.Y + b.Y);
}
public static Vector2D operator -(Vector2D a, Vector2D b)
{
return new Vector2D(a.X - b.X, a.Y - b.Y);
}
}
```
## 6.控制结构
### 6.1 条件控制结构
if
```c#
if (条件表达式)
{
// 条件为真时执行的代码
}
if (条件表达式)
{
// 条件为真时执行
}
else
{
// 条件为假时执行
}
if (条件1)
{
// 条件1为真时执行
}
else if (条件2)
{
// 条件2为真时执行
}
else
{
// 所有条件为假时执行
}
```
switch
```c#
switch (表达式)
{
case 值1:
// 代码块1
break;
case 值2:
// 代码块2
break;
default:
// 默认代码块
break;
}
// 7.0+ 增强特性
switch (shape)
{
case Circle c:
Console.WriteLine($"圆形,半径={c.Radius}");
break;
case Rectangle r when r.Width == r.Height:
Console.WriteLine($"正方形,边长={r.Width}");
break;
case null:
throw new ArgumentNullException(nameof(shape));
default:
Console.WriteLine("未知形状");
break;
}
```
### 6.2 循环控制
for
```c#
for (初始化; 条件; 迭代)
{
// 循环体
}
// 示例
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
```
while
```c#
while (条件表达式)
{
// 循环体
}
// 示例
int i = 0;
while (i < 10)
{
Console.WriteLine(i);
i++;
}
```
do-while
```c#
do
{
// 循环体(至少执行一次)
} while (条件表达式);
// 示例
int i = 0;
do
{
Console.WriteLine(i);
i++;
} while (i < 10);
```
foreach
```c#
foreach (类型 变量 in 集合)
{
// 循环体
}
// 示例
string[] names = { "Alice", "Bob", "Charlie" };
foreach (string name in names)
{
Console.WriteLine(name);
}
```
### 6.3 跳转语句
**break**
立即终止当前循环或switch语句
```c#
for (int i = 0; i < 10; i++)
{
if (i == 5)
break; // 当i=5时退出循环
Console.WriteLine(i);
}
```
**continue**
跳过当前循环迭代,继续下一次迭代
```c#
for (int i = 0; i < 10; i++)
{
if (i % 2 == 0)
continue; // 跳过偶数
Console.WriteLine(i);
}
```
**return**
立即退出当前方法,并可返回一个值
```c#
int Add(int a, int b)
{
return a + b; // 返回计算结果
}
```
**goto**
```c#
for (int i = 0; i < 10; i++)
{
if (i == 5)
goto EndLoop; // 跳转到标签处
Console.WriteLine(i);
}
EndLoop:
Console.WriteLine("循环结束");
```
### 6.4 特殊控制结构
try-catch-finally
```c#
try
{
// 可能抛出异常的代码
}
catch (特定异常类型 ex)
{
// 处理特定异常
}
catch (Exception ex)
{
// 处理所有其他异常
}
finally
{
// 无论是否发生异常都会执行的代码
}
```
using
```c#
using (var resource = new DisposableResource())
{
// 使用资源
// 离开作用域时自动调用Dispose(),在处理IO流相关操作时用到
}
```
yield return
```c#
IEnumerable<int> GetNumbers()
{
for (int i = 0; i < 10; i++)
{
yield return i; // 延迟生成值
}
}
```
### 6.5 C# 8.0+ 新特性
switch
```c#
var result = operation switch
{
"+" => a + b,
"-" => a - b,
"*" => a * b,
"/" => a / b,
_ => throw new InvalidOperationException("未知运算符")
};
```
模式匹配增强
```c#
if (obj is string { Length: >5 } s)
{
Console.WriteLine($"长字符串: {s}");
}
```
异步流
```c#
await foreach (var item in GetAsyncItems())
{
Console.WriteLine(item);
}
```
## 7.数组
### 7.1 数组基础概念
7.1.1 数组核心特性
- 固定大小:创建后长度不可变
- 类型统一:所有元素必须是相同类型
- 连续内存:元素在内存中顺序存储
- 索引访问:通过下标访问元素(从0开始)
- 性能优势:访问速度快(O(1)),缓存友好
7.1.2 数组分类
- 一维数组:int[]
- 多维数组:int[,](矩形数组)
- 锯齿数组:int[][](数组的数组)
### 7.2 数组声明与初始化
基本语法
```c#
// 方式1:声明后初始化
int[] numbers1;
numbers1 = new int[5]; // 5个元素,默认值0
// 方式2:声明时初始化
int[] numbers2 = new int[] {1, 2, 3};
// 方式3:简化初始化
int[] numbers3 = {1, 2, 3, 4, 5};
// 方式4:指定大小
int[] numbers4 = new int[5] {1, 2, 3, 4, 5};
```
多维数组
```c#
// 二维数组(矩形数组)
int[,] matrix = new int[3,4]; // 3行4列
// 初始化二维数组
int[,] matrix2 = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 访问元素
int val = matrix2[1,2]; // 第2行第3列(6)
```
锯齿数组
```c#
// 声明锯齿数组
int[][] jagged = new int[3][];
// 初始化子数组
jagged[0] = new int[2] {1, 2};
jagged[1] = new int[3] {3, 4, 5};
jagged[2] = new int[4] {6, 7, 8, 9};
// 访问元素
int item = jagged[1][2]; // 5
```
### 7.3 数组操作
基本操作
```c#
int[] arr = {1, 2, 3, 4, 5};
// 访问元素
int first = arr[0]; // 1
// 修改元素
arr[1] = 10; // 数组变为[1,10,3,4,5]
// 获取长度
int len = arr.Length; // 5
// 遍历数组
for (int i = 0; i < arr.Length; i++) {
Console.WriteLine(arr[i]);
}
foreach (int num in arr) {
Console.WriteLine(num);
}
```
数组复制
```c#
int[] source = {1, 2, 3};
int[] dest = new int[3];
// 方法1:Array.Copy
Array.Copy(source, dest, source.Length);
// 方法2:Clone方法
int[] clone = (int[])source.Clone();
// 方法3:CopyTo
source.CopyTo(dest, 0);
```
数组排序与搜索
```c#
int[] numbers = {5, 3, 9, 1, 7};
// 快速排序
Array.Sort(numbers); // [1, 3, 5, 7, 9]
// 部分排序
Array.Sort(numbers, 1, 3); // 排序索引1开始的3个元素
// 自定义排序
Array.Sort(numbers, (x, y) => y.CompareTo(x)); // 降序[9,7,5,3,1]
// 二分查找(必须先排序)
int index = Array.BinarySearch(numbers, 7); // 返回3
if (index >= 0) {
Console.WriteLine($"找到元素,位置:{index}");
}
```
数组转换
```c#
// 类型转换
object[] objArray = {1, "two", 3.0};
int[] intArray = Array.ConvertAll(objArray, x => Convert.ToInt32(x));
// 使用LINQ转换
var strArray = numbers.Select(x => x.ToString()).ToArray();
```
### 7.4 数组高级
**数组协变(仅适用于引用类型)**
```c#
object[] objArr = new string[10]; // 合法
// objArr[0] = 5; // 运行时抛出ArrayTypeMismatchException
```
**数组初始化器**
```c#
// 多维数组初始化
int[,] matrix = {
{1, 2, 3},
{4, 5, 6}
};
// 锯齿数组初始化
int[][] jagged = {
new int[] {1, 2},
new int[] {3, 4, 5}
};
```
**数组与Span**
Span:内存中连续的数据
```c#
int[] arr = {1, 2, 3, 4, 5};
// 创建Span
Span<int> span = arr.AsSpan();
// 切片操作
Span<int> slice = span.Slice(1, 3); // [2,3,4]
slice[0] = 10; // 原数组变为[1,10,3,4,5]
```
**数组与指针(unsafe)**
```c#
unsafe {
int[] arr = {1, 2, 3};
fixed (int* ptr = arr) {
for (int i = 0; i < arr.Length; i++) {
Console.WriteLine(*(ptr + i));
}
}
}
```
### 7.5 数组实用技巧
数组比较
```c#
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
// 比较引用
bool sameRef = arr1 == arr2; // false
// 比较内容
bool sameContent = arr1.SequenceEqual(arr2); // true
```
数组填充
```c#
int[] arr = new int[5];
Array.Fill(arr, 1); // [1,1,1,1,1]
// 部分填充
Array.Fill(arr, 0, 1, 3); // [1,0,0,0,1]
```
数组反转
```c#
int[] arr = {1, 2, 3, 4};
Array.Reverse(arr); // [4,3,2,1]
// 部分反转
Array.Reverse(arr, 1, 2); // [4,2,3,1]
```
数组清空
```c#
int[] arr = {1, 2, 3};
Array.Clear(arr, 0, arr.Length); // 所有元素设为0
```
## 8.集合
### 8.1 集合核心概念
集合与数组的区别
|特性 |数组 |集合|
|-|-|-|
|大小 |固定| 动态可变|
|功能| 基础操作 |丰富的数据操作方法|
|内存 |连续存储| 可能非连续|
|性能 |访问快(O(1)) |不同集合性能差异大|
|类型安全 |同类型元素 |泛型集合保证类型安全|
集合分类体系
```c#
IEnumerable<T> (可枚举)
├── ICollection<T> (基础集合)
│ ├── IList<T> (有序集合)
│ └── ISet<T> (唯一性集合)
└── IDictionary<TKey,TValue> (键值集合)
```
### 8.2 List
**核心特性**
动态数组:基于数组自动扩容
泛型支持:类型安全
丰富API:提供排序、搜索等操作
索引访问:支持下标访问(O(1))
默认构造初始容量为0,首次添加时扩容到4, 新容量 = 旧容量 * 2
**关键操作及时间复杂度**
|操作 |方法 |时间复杂度|
|-|-|-|
|添加元素 |Add(item)| 平均O(1)|
|批量添加| AddRange(items) |O(n)|
|插入元素 |Insert(index,item)| O(n)|
|删除元素| Remove(item)| O(n)|
|按索引删除 |RemoveAt(index)| O(n)|
|查找元素 |Contains(item)| O(n)|
|索引访问| [index] |O(1)|
**性能优化**
```c#
// 1. 预分配容量
var list = new List<int>(10000);
// 2. 批量操作优于单个操作
list.AddRange(Enumerable.Range(1,1000));
// 3. 使用Capacity属性
list.Capacity = list.Count; // 释放多余空间
// 4. 排序优化
list.Sort(); // 快速排序 O(n log n)
```
### 8.3 Dictionary
**哈希表实现原理**
桶数组:存储链表头节点
哈希函数:GetHashCode()计算位置
冲突解决:链地址法处理碰撞
扩容机制:当元素数 > 容量*负载因子(默认0.75)时扩容
**核心操作**
```c#
Dictionary<string, int> dict = new Dictionary<string, int>();
// 添加元素(平均O(1))
dict.Add("Alice", 25);
dict["Bob"] = 30; // 替代语法
// 安全访问(避免异常)
if (dict.TryGetValue("Charlie", out int age)) {
// 处理获取的值
}
// 删除键(平均O(1))
dict.Remove("Alice");
// 遍历方式
foreach (KeyValuePair<string, int> kvp in dict) {
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
```
**碰撞与性能优化**
```c#
// 1. 实现良好的Equals以及GetHashCode()
public class Person
{
public string? Name { get; set; }
public int Age { get; set; }
public override bool Equals(object? obj)
{
return obj is Person person &&
Name == person.Name &&
Age == person.Age;
}
public override int GetHashCode()
{
return HashCode.Combine(Name, Age);
}
}
// 2. 设置初始容量
var bigDict = new Dictionary<string, int>(100000);
// 3. 避免频繁扩容
dict.EnsureCapacity(50000);
```
### 8.4 HashSet 与 SortedSet
**HashSet**
特性:
- 唯一元素:自动去重
- 哈希实现:基于Dictionary实现
- 集合运算:支持并/交/差集
```c#
HashSet<int> setA = new HashSet<int>{1, 2, 3};
HashSet<int> setB = new HashSet<int>{3, 4, 5};
// 集合运算
setA.UnionWith(setB); // 并集 {1,2,3,4,5}
setA.IntersectWith(setB); // 交集 {3}
setA.ExceptWith(setB); // 差集 {1,2}
```
**SortedSet**
- 红黑树实现:元素自动排序
- 范围查询:支持获取子集
- 查找效率:O(log n)
```c#
SortedSet<int> sorted = new SortedSet<int>{5, 3, 9};
// 获取范围视图
var subset = sorted.GetViewBetween(3, 7); // [3,5]
// 最小最大值
int min = sorted.Min; // 3
int max = sorted.Max; // 9
```
### 8.5 Queue与Stack
**队列Queue**
```c#
Queue<string> queue = new Queue<string>();
// 入队
queue.Enqueue("First");
queue.Enqueue("Second");
// 出队
string item = queue.Dequeue(); // "First"
// 查看队首
string peek = queue.Peek(); // "Second"
```
**栈Stack**
```c#
Stack<int> stack = new Stack<int>();
// 压栈
stack.Push(1);
stack.Push(2);
// 弹栈
int top = stack.Pop(); // 2
// 查看栈顶
int current = stack.Peek(); // 1
```
### 8.6 线程安全集合
**Concurrent Collections**
```c#
// 1. 并发字典
ConcurrentDictionary<int, string> concurrentDict = new ConcurrentDictionary<int, string>();
concurrentDict.TryAdd(1, "Value");
// 2. 并发队列
ConcurrentQueue<int> concurrentQueue = new ConcurrentQueue<int>();
concurrentQueue.Enqueue(10);
// 3. 并发栈
ConcurrentStack<int> concurrentStack = new ConcurrentStack<int>();
concurrentStack.Push(20);
// 4. 并发包(无序集合)
ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
concurrentBag.Add(30);
```
**同步包装器**
```c#
// 创建线程安全集合
var syncList = System.Collections.Synchronized(new List<int>());
var syncDict = System.Collections.Synchronized(new Dictionary<int, string>());
// 使用时仍需lock保证原子操作
lock (syncList.SyncRoot) {
syncList.Add(1);
}
```
### 8.7 性能优化
预分配容量:减少扩容操作
```c#
new List<int>(1000);
new Dictionary<string,int>(5000);
```
避免装箱拆箱:使用泛型集合
```c#
// 错误:ArrayList导致装箱
ArrayList badList = new ArrayList();
badList.Add(1); // 装箱
// 正确:List<T>避免装箱
List<int> goodList = new List<int>();
goodList.Add(1); // 无装箱
```
批量操作:减少方法调用开销
```c#
// 优于多次Add
list.AddRange(items);
```
LINQ延迟执行:及时物化查询
```c#
// 立即执行
var result = source.Where(x => x > 0).ToList();
```
## 9.字符串
### 9.1 字符串基础
9.1.1 字符串特性
- 不可变性(Immutable):字符串一旦创建就不能修改,所有"修改"操作都返回新字符串
- 引用类型:但具有值类型的某些特性
- Unicode编码:支持多语言字符
- 字符串池(String Interning):CLR对字面量字符串的优化机制
9.1.2 字符串创建方式
```c#
// 1. 直接赋值
string s1 = "Hello World";
// 2. 使用构造函数
char[] letters = { 'H', 'e', 'l', 'l', 'o' };
string s2 = new string(letters); // "Hello"
// 3. 重复字符
string s3 = new string('a', 5); // "aaaaa"
// 4. 从指针创建(unsafe)
unsafe {
fixed (char* p = letters) {
string s4 = new string(p); // "Hello"
}
}
```
### 9.2 字符串常用操作
**9.2.1 基本操作**
```C#
// 长度获取
int len = "Hello".Length; // 5
// 索引访问
char first = "Hello"[0]; // 'H'
// 连接字符串
string concat = "Hello" + " " + "World"; // "Hello World"
// 大小写转换
string upper = "Hello".ToUpper(); // "HELLO"
string lower = "Hello".ToLower(); // "hello"
```
**9.2.2 字符串比较**
```C#
// 1. 值比较
bool equal = "Hello".Equals("hello"); // false
bool ignoreCase = "Hello".Equals("hello", StringComparison.OrdinalIgnoreCase); // true
// 2. Compare方法
int result = string.Compare("A", "B"); // -1 (A < B)
// 3. CompareTo方法
int result2 = "A".CompareTo("B"); // -1
// 4. 运算符
bool opEqual = "A" == "A"; // true
```
**9.2.3 字符串查找**
```C#
string text = "Hello World";
// 查找索引
int index1 = text.IndexOf('o'); // 4
int index2 = text.IndexOf("World"); // 6
int index3 = text.LastIndexOf('o'); // 7
// 检查包含
bool contains = text.Contains("World"); // true
// 开头/结尾检查
bool starts = text.StartsWith("Hello"); // true
bool ends = text.EndsWith("ld"); // true
```
**9.2.4 字符串修改**
```C#
string original = "Hello World";
// 截取
string sub1 = original.Substring(6); // "World"
string sub2 = original.Substring(0, 5); // "Hello"
// 插入
string inserted = original.Insert(5, " Beautiful"); // "Hello Beautiful World"
// 移除
string removed = original.Remove(5, 6); // "Hello"
// 替换
string replaced = original.Replace("World", "C#"); // "Hello C#"
// 修剪空白
string trimmed = " Hello ".Trim(); // "Hello"
string trimStart = " Hello ".TrimStart(); // "Hello "
string trimEnd = " Hello ".TrimEnd(); // " Hello"
```
### 9.3 字符串格式化
**9.3.1 复合格式化**
```C#
string.Format("Name: {0}, Age: {1}", "Alice", 25);
// "Name: Alice, Age: 25"
```
**9.3.2 字符串插值(C# 6.0+)**
```C#
string name = "Alice";
int age = 25;
string result = $"Name: {name}, Age: {age}";
// "Name: Alice, Age: 25"
```
**9.3.3 数值格式化**
```C#
// 数字格式化
string.Format("{0:N2}", 1234.5678); // "1,234.57"
string.Format("{0:D5}", 42); // "00042"
string.Format("{0:C}", 19.99); // "$19.99"
// 日期格式化
DateTime now = DateTime.Now;
string.Format("{0:yyyy-MM-dd}", now); // "2023-06-15"
```
### 9.4 字符串高级特性
**9.4.1 字符串构建器(StringBuilder)**
```C#
StringBuilder sb = new StringBuilder();
sb.Append("Hello");
sb.AppendLine(" World");
sb.AppendFormat("Today is {0:yyyy-MM-dd}", DateTime.Now);
string result = sb.ToString();
```
**9.4.2 字符串池(Interning)**
```C#
string a = "Hello";
string b = "Hello";
string c = new string(new[] { 'H', 'e', 'l', 'l', 'o' });
Console.WriteLine(object.ReferenceEquals(a, b)); // True (字符串池)
Console.WriteLine(object.ReferenceEquals(a, c)); // False
// 手动驻留
string d = string.Intern(c);
Console.WriteLine(object.ReferenceEquals(a, d)); // True
```
**9.4.3 逐字字符串(@)与转义字符**
```C#
// 普通字符串
string path1 = "C:\\Windows\\System32"; // 需要转义
// 逐字字符串
string path2 = @"C:\Windows\System32"; // 不需要转义
// 多行字符串
string multiLine = @"Line 1
Line 2
Line 3";
```
### 9.5 字符串编码与转换
**9.5.1 编码转换**
```C#
// 字符串转字节数组
byte[] utf8Bytes = Encoding.UTF8.GetBytes("Hello");
byte[] unicodeBytes = Encoding.Unicode.GetBytes("Hello");
// 字节数组转字符串
string fromUtf8 = Encoding.UTF8.GetString(utf8Bytes);
string fromUnicode = Encoding.Unicode.GetString(unicodeBytes);
```
**9.5.2 Base64编码**
```C#
// 编码
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes("Hello"));
// 解码
string original = Encoding.UTF8.GetString(Convert.FromBase64String(base64));
```
### 9.6 字符串性能优化
**9.6.1 避免不必要的字符串操作**
```C#
// 不好:创建多个临时字符串
string result = "";
for (int i = 0; i < 100; i++) {
result += i.ToString();
}
// 好:使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
sb.Append(i);
}
string finalResult = sb.ToString();
```
**9.6.2 比较优化**
```C#
// 不好:区分大小写的比较
if (input.ToLower() == "admin") { ... }
// 好:使用比较选项
if (input.Equals("admin", StringComparison.OrdinalIgnoreCase)) { ... }
```
**9.6.3 字符串分割优化**
```C#
// 不好:多次分割
string[] parts1 = csv.Split(',');
string[] parts2 = csv.Split(';');
// 好:一次性分割
char[] separators = { ',', ';' };
string[] parts = csv.Split(separators);
```
### 9.7 正则表达式
**9.7.1 基本用法**
```C#
using System.Text.RegularExpressions;
string pattern = @"\d+"; // 匹配数字
Regex regex = new Regex(pattern);
bool isMatch = regex.IsMatch("abc123"); // true
Match match = regex.Match("abc123");
string value = match.Value; // "123"
```
**9.7.2 常用模式**
```C#
// 电子邮件验证
bool isEmail = Regex.IsMatch(input, @"^[^@\s]+@[^@\s]+\.[^@\s]+$");
// 提取数字
MatchCollection matches = Regex.Matches("a1b2c3", @"\d");
foreach (Match m in matches) {
Console.WriteLine(m.Value); // 1, 2, 3
}
// 替换
string clean = Regex.Replace("a1b2c3", @"\d", "_"); // "a_b_c_"
```
### 9.8 字符串安全
敏感信息处理
```C#
// 使用SecureString处理密码等敏感信息
SecureString securePwd = new SecureString();
foreach (char c in "password") {
securePwd.AppendChar(c);
}
// 使用后立即清除
securePwd.Dispose();
```
## 10.控制台(Console )
### 10.1 基础
**10.1.1 Console 概述**
System.Console 类提供对标准输入、输出和错误流的访问
主要用于控制台应用程序的输入输出操作
所有方法都是静态的,无需实例化
**10.1.2 基本输入输出**
输出文本
```C#
Console.Write("Hello"); // 不换行输出
Console.WriteLine("World"); // 输出后换行
```
读取输入
```C#
string input = Console.ReadLine(); // 读取一行输入
int key = Console.Read(); // 读取单个字符(返回ASCII码)
ConsoleKeyInfo keyInfo = Console.ReadKey(); // 读取按键信息
```
### 10.2 格式化输出
**10.2.1 复合格式化**
```C#
string name = "Alice";
int age = 25;
Console.WriteLine("Name: {0}, Age: {1}", name, age);
```
**10.2.2 字符串插值(C# 6.0+)**
```C#
Console.WriteLine($"Name: {name}, Age: {age}");
```
**10.2.3 数值格式化**
```C#
double num = 1234.5678;
Console.WriteLine("{0:N2}", num); // 1,234.57
Console.WriteLine("{0:C}", 19.99); // $19.99
Console.WriteLine("{0:D5}", 42); // 00042
```
### 10.3 控制台颜色设置
**10.3.1 颜色属性**
```C#
Console.ForegroundColor = ConsoleColor.Red; // 前景色(文本)
Console.BackgroundColor = ConsoleColor.White; // 背景色
Console.ResetColor(); // 重置为默认颜色
```
**10.3.2 颜色示例**
```C#
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("警告信息");
Console.ResetColor();
```
### 10.4 控制台窗口控制
**10.4.1 窗口属性**
可能只在windows生效
```C#
Console.WindowWidth = 80; // 设置窗口宽度
Console.WindowHeight = 30; // 设置窗口高度
Console.BufferWidth = 100; // 设置缓冲区宽度
Console.BufferHeight = 1000; // 设置缓冲区高度
Console.Title = "我的控制台"; // 设置窗口标题
```
**10.4.2 光标控制**
```C#
Console.CursorVisible = false; // 隐藏光标
Console.SetCursorPosition(10, 5); // 设置光标位置(列,行)
Console.CursorLeft = 20; // 设置光标列位置
Console.CursorTop = 10; // 设置光标行位置
```
### 10.5 高级功能
**10.5.1 控制台铃声**
```C#
Console.Beep(); // 默认频率和时长
Console.Beep(800, 200); // 频率(Hz), 时长(ms)
```
**10.5.2 编码设置**
```C#
Console.OutputEncoding = Encoding.UTF8; // 设置输出编码
Console.InputEncoding = Encoding.UTF8; // 设置输入编码
```
**10.5.3 清屏与进度显示**
```C#
Console.Clear(); // 清空控制台
// 简单进度条
for (int i = 0; i <= 100; i++)
{
Console.Write($"\r进度: {i}% "); // \r回到行首
Thread.Sleep(50);
}
```
## 11.异常处理
### 11.1 异常处理基础
**11.1.1 异常概念**
异常:程序执行期间发生的意外情况
异常类:所有异常都继承自System.Exception
异常处理:捕获并处理异常,防止程序崩溃
**11.1.2 常见异常类型**
|异常类型| 描述|
|-|-|
|NullReferenceException |尝试访问null对象成员|
|IndexOutOfRangeException| 数组/集合索引越界|
|ArgumentException| 方法参数无效|
|FormatException |格式转换失败|
|IOException| I/O操作错误|
|DivideByZeroException| 除零错误|
### 11.2 基本异常处理结构
** 11.2.1 try-catch 块**
```C#
try
{
// 可能抛出异常的代码
int result = 10 / int.Parse("0");
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"除零错误: {ex.Message}");
}
catch (FormatException ex)
{
Console.WriteLine($"格式错误: {ex.Message}");
}
```
**11.2.2 finally**
```C#
FileStream file = null;
try
{
file = File.Open("test.txt", FileMode.Open);
// 文件操作
}
catch (IOException ex)
{
Console.WriteLine($"IO错误: {ex.Message}");
}
finally
{
file?.Close(); // 确保资源释放
}
```
**11.2.3 throw 语句**
```C#
// 重新抛出当前异常
catch (Exception ex)
{
Console.WriteLine("记录错误");
throw; // 保留原始调用栈
}
// 抛出新异常
if (value < 0)
throw new ArgumentException("值不能为负");
```
### 11.3 异常处理高级特性
**11.3.1 异常筛选器 (C# 6.0+)**
```C#
try { /* ... */ }
catch (Exception ex) when (ex.Message.Contains("特定错误"))
{
// 仅当条件满足时捕获
}
```
**11.3.2 自定义异常**
```C#
public class InvalidAccountException : Exception
{
public InvalidAccountException() { }
public InvalidAccountException(string message) : base(message) { }
public InvalidAccountException(string message, Exception inner)
: base(message, inner) { }
}
// 使用自定义异常
throw new InvalidAccountException("账户无效");
```
**11.3.3 异常数据字典**
```C#
try { /* ... */ }
catch (Exception ex)
{
ex.Data.Add("Timestamp", DateTime.Now);
ex.Data.Add("User", "Admin");
throw;
}
```
### 11.4 异常处理与资源管理
**11.4.1 using 语句**
```C#
using (var resource = new DisposableResource())
{
// 自动调用Dispose(),即使抛出异常
}
```
**11.4.2 模式匹配 (C# 7.0+)**
```C#
try { /* ... */ }
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
Console.WriteLine("文件访问错误");
}
```
# 二.面向对象编程
## 1.类与对象
### 1.1 类和对象的基本概念
**类 (Class)**
- 类是创建对象的蓝图或模板
- 定义了对象的属性和行为
- 是面向对象编程的基本构建块
**对象 (Object)**
- 对象是类的实例
- 每个对象都有自己的状态(属性值)和行为(方法)
- 对象通过new关键字创建
```c#
// 定义一个类
public class Person
{
// 类的成员
}
// 创建对象
Person person1 = new Person();
```
### 1.2 类的成员
**1.2.1 字段 (Fields)**
- 存储类或对象的数据
- 通常设为私有(private),通过属性访问
```c#
private string _name;
private int _age;
```
**1.2.2 属性 (Properties)**
- 提供对字段的安全访问
- 可以包含get和set访问器
```c#
private string _name;
public string Name
{
get { return _name; }
set { _name= value; }
}
// 自动属性(C# 3.0+)
public int Age { get; set; }
```
**1.2.3 方法 (Methods)**
- 定义类的行为
- 可以接受参数并返回值
```c#
public void SayHello()
{
Console.WriteLine($"Hello, my name is {Name}");
}
public int CalculateAgeInMonths()
{
return Age * 12;
}
```
**1.2.4 构造函数 (Constructors)**
- 用于初始化对象
- 与类同名,没有返回类型
- 可以重载
```c#
public Person()
{
// 默认构造函数
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
```
### 1.3 文档注释
为公共方法,属性添加注释,该注释能辅助编写代码时鼠标放上去查看解释
```c#
/// <summary>
/// 计算两个数的和
/// </summary>
/// <param name="a">第一个加数</param>
/// <param name="b">第二个加数</param>
/// <returns>两数之和</returns>
public int Add(int a, int b)
{
return a + b;
}
```
### 1.4 访问修饰符
|关键字| 描述|
|-|-|
|public| 访问不受限制|
|private| 只能在当前类中访问|
|protected |只能在当前类或派生类中访问|
|internal| 只能在当前程序集中访问|
|protected internal |在当前程序集或派生类中可访问|
|private protected |在当前程序集的派生类中可访问|
|file |仅在当前文件中可访问|
### 1.5 静态成员
- 属于类而不是对象
- 通过类名访问,而不是对象实例
- 常用于工具类或共享数据
```c#
public class MathUtility
{
public static double PI = 3.14159;
public static int Add(int a, int b)
{
return a + b;
}
}
// 使用静态成员
double pi = MathUtility.PI;
int sum = MathUtility.Add(5, 3);
```
### 1.6 静态类
静态类是一种特殊的类,具有以下核心特征:
- 不能被实例化(不能使用new创建对象)
- 只能包含静态成员(静态字段、静态方法、静态属性等)
- 隐式密封:静态类隐式是sealed的,尝试继承会编译错误
```c#
public static class MathUtility
{
public static double PI = 3.14159;
}
// 使用静态成员
double pi = MathUtility.PI;
```
### 1.7 静态构造函数
- 在首次访问类时自动执行
- 每个应用程序域只执行一次
- 没有访问修饰符和参数
```c#
public class Logger
{
private static readonly string logFile;
// 静态构造函数
static Logger()
{
logFile = $"log_{DateTime.Now:yyyyMMdd}.txt";
Console.WriteLine("Logger初始化完成");
}
public static void Log(string message) { /*...*/ }
}
```
### 1.8 析构函数/终结器
- 在对象销毁前执行清理操作
- 不能手动调用,由垃圾回收器自动调用
```c#
~Person()
{
// 清理代码
}
```
**现代对象销毁设计**
```c#
public class Resource : IDisposable
{
public void Dispose()
{
// 确定性释放资源
}
}
// 使用示例
using (var res = new Resource())
{
// 自动调用Dispose()
}
```
### 1.9 ref、out
**1.9.1 值传递 vs 引用传递**
默认行为:C# 方法参数默认是值传递(传递副本)
```c#
void Modify(int x) { x = 100; }
int num = 10;
Modify(num); // num 仍然是10
```
**1.9.2 ref 关键字**
实现引用传递,方法内修改会影响原始变量,调用前必须初始化变量,方法声明和调用时都要加 ref。
```c#
void ModifyRef(ref int x) { x = 100; }
int num = 10;
ModifyRef(ref num); // num 变为100
```
**1.9.3 out 关键字**
用于从方法返回多个值(类似引用传递),调用前无需初始化变量,方法内必须赋值给out参数,方法声明和调用时都要加 out。
```c#
bool TryParse(string s, out int result) {
if (int.TryParse(s, out result)) {
return true;
}
return false;
}
int parsedValue;
if (TryParse("123", out parsedValue)) {
Console.WriteLine(parsedValue); // 输出123
}
```
### 1.10 运算符重载
```c#
public class Vector2D
{
public double X { get; set; }
public double Y { get; set; }
public Vector2D(double x, double y)
{
X = x;
Y = y;
}
public static Vector2D operator +(Vector2D a, Vector2D b)
{
return new Vector2D(a.X + b.X, a.Y + b.Y);
}
public static Vector2D operator -(Vector2D a, Vector2D b)
{
return new Vector2D(a.X - b.X, a.Y - b.Y);
}
}
public static void Main(string[] args)
{
Vector2D v1 = new Vector2D(1, 2);
Vector2D v2 = new Vector2D(3, 4);
var n = (v1 + v2);
Console.WriteLine($"new x:{n.X},new y:{n.Y}");
}
```
### 1.11 this关键字
**1.11.1 类索引器**
索引器(Indexer)是 C# 中的一种特殊成员,它允许类的实例像数组一样通过索引来访问。索引器类似于属性,但使用索引参数而不是属性名。
```c#
public class StringArray
{
private string[] array = new string[10];
// 索引器定义
public string this[int index]
{
get
{
if (index < 0 || index >= array.Length)
throw new IndexOutOfRangeException();
return array[index];
}
set
{
if (index < 0 || index >= array.Length)
throw new IndexOutOfRangeException();
array[index] = value;
}
}
}
// 使用示例
StringArray myArray = new StringArray();
myArray[0] = "Hello"; // 调用set访问器
Console.WriteLine(myArray[0]); // 调用get访问器,输出"Hello"
public class Matrix
{
private int[,] data = new int[10, 10];
public int this[int row, int col]
{
get { return data[row, col]; }
set { data[row, col] = value; }
}
}
// 使用示例
Matrix matrix = new Matrix();
matrix[0, 0] = 1;
Console.WriteLine(matrix[0, 0]); // 输出1
```
**1.11.2 链式构造和指代当前**
```c#
public class User
{
string uuid;
string username;
string password;
public User()
{
uuid = Guid.NewGuid().ToString();
}
/// <summary>
/// :this() 调用默认无参构造函数
/// </summary>
/// <param name="username"></param>
public User(string username):this()
{
// 指示前传入的username赋值给当对象的username
this.username = username;
}
public User(string username,string password):this(username)
{
this.password = password;
}
}
```
**1.11.3 类拓展**
```c#
public class Program
{
public static void Main(string[] args)
{
List<string> breakfast = new List<string>()
{
"煎饼果子",
"包子",
"油条",
"豆浆",
"稀饭",
"炒饭",
"炒面",
"蛋挞",
"牛奶",
"面包",
};
Console.WriteLine($"今早吃:{breakfast.GetRandomItem()}");
}
}
public static class ListExpand
{
private readonly static Random random=new Random();
public static T GetRandomItem<T>(this List<T> list)
{
return list[random.Next(0, list.Count)];
}
}
```
### 1.12 部分类
将一个类分为两个文件编写,编译后为一个类
```c#
// File1.cs
public partial class MyClass
{
public void Method1() { }
}
// File2.cs
public partial class MyClass
{
public void Method2() { }
}
```
### 1.13 对象初始化器
```c#
// Name 和 Age 为公开可写的属性
Person person = new Person
{
Name = "John",
Age = 30
};
```
### 1.14 只读属性和只读字段
```c#
public class MyClass
{
/// <summary>
/// 只读字段:只能进行读取,无法重新赋值,且只能在构造函数中或字段上初始化
/// </summary>
private readonly List<string> _list = new List<string>();
private readonly List<string> _list2;
/// <summary>
/// 只读属性:外部只能读取,不能修改
/// </summary>
public List<string> List3 { get; } = new List<string>();
public MyClass()
{
_list2 = new List<string>();
}
}
```
## 2.面向对象
### 2.1 面向对象三大特性
- 封装:隐藏对象内部细节,仅暴露必要接口
- 继承:子类继承父类特征和行为
- 多态:同一操作作用于不同对象产生不同行为
### 2.2 封装
两个核心思想:
- 数据隐藏:将对象的内部状态(数据)隐藏起来,不允许外部直接访问
- 行为暴露:通过公共方法(接口)提供对数据的受控访问
简单的封装示例:
```c#
public class User
{
/// <summary>
/// 自动属性,仅限内部使用
/// </summary>
public int Id { get; private set; }
/// <summary>
/// 私有字段,外部无法访问
/// </summary>
private string _username;
/// <summary>
/// 提供公开的访问属性进行暴露
/// </summary>
public string Username{
get => _username;
}
/// <summary>
/// 通过方法进行暴露
/// </summary>
/// <returns></returns>
public string GetUsername()
{
return _username;
}
/// <summary>
/// 设置用户名
/// </summary>
public void SetUsername(string username,string code)
{
if(string.IsNullOrEmpty(username)||string.IsNullOrEmpty(code)||!string.Equals(code,"123456"))
{
throw new ArgumentException("Username错误");
}
_username = username;
}
}
```
### 2.3 继承
基于现有类创建新类,实现代码的重用和扩展
- 基类/父类:被继承的类
- 派生类/子类:继承自基类的新类
- "is-a"关系:子类是父类的一种特殊类型
**继承的基本语法**
```c#
// 基类(父类)
public class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}
// 派生类(子类)
public class Dog : Animal // 使用冒号表示继承
{
public void Bark()
{
Console.WriteLine($"{Name} is barking.");
}
}
```
**成员继承**
1.子类自动获得父类的所有非私有成员(字段、属性、方法)
2.私有成员(private)不会被继承
**构造函数继承**
```c#
public class Animal
{
public string Name { get; }
// 基类构造函数
public Animal(string name)
{
Name = name;
}
}
public class Dog : Animal
{
public string Breed { get; }
// 派生类构造函数必须调用基类构造函数
public Dog(string name, string breed) : base(name) // 使用base关键字
{
Breed = breed;
}
}
```
**方法重写(虚方法)**
```c#
public class Animal
{
public virtual void MakeSound() // virtual关键字表示可重写
{
Console.WriteLine("Some generic animal sound");
}
}
public class Dog : Animal
{
public override void MakeSound() // override关键字表示重写
{
Console.WriteLine("Woof! Woof!");
}
}
// 使用
Animal myDog = new Dog();
myDog.MakeSound(); // 输出 "Woof! Woof!" (多态)
```
**隐藏方法(new关键字)**
```c#
public class Animal
{
public void Sleep()
{
Console.WriteLine("Animal is sleeping");
}
}
public class Dog : Animal
{
public new void Sleep() // new关键字隐藏基类方法
{
Console.WriteLine("Dog is sleeping");
}
}
// 使用
Animal animal = new Dog();
animal.Sleep(); // 输出 "Animal is sleeping" (没有多态)
Dog dog = new Dog();
dog.Sleep(); // 输出 "Dog is sleeping"
```
只有重写才有多态效果,方法重叠和隐藏方法都不行
**密封类和密封方法**
```c#
public sealed class FinalClass // sealed关键字表示不能被继承
{
// 类成员
}
public class BaseClass
{
public virtual void Method()
{
// 可重写的方法
}
}
public class DerivedClass : BaseClass
{
public sealed override void Method() // 密封方法,不能再被重写
{
// 方法实现
}
}
```
**多继承与接口**
C#不支持多类继承,但可以通过接口实现
```c#
public interface IMovable
{
void Move();
}
public interface ISpeakable
{
void Speak();
}
public class Robot : IMovable, ISpeakable // 实现多个接口
{
public void Move()
{
Console.WriteLine("Robot is moving");
}
public void Speak()
{
Console.WriteLine("Beep boop");
}
}
```
### 2.4 多态
**编译时多态(方法重载)**
```c#
public class Calculator
{
// 方法重载:相同方法名,不同参数列表
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}
public int Add(int a, int b, int c)
{
return a + b + c;
}
}
// 使用
var calc = new Calculator();
Console.WriteLine(calc.Add(1, 2)); // 调用int版本
Console.WriteLine(calc.Add(1.5, 2.5)); // 调用double版本
Console.WriteLine(calc.Add(1, 2, 3)); // 调用三参数版本
```
**运行时多态(方法重写)**
## 3.接口
接口是C#中一种引用类型,它定义了一组相关功能的契约(合同),但不提供具体实现
- 纯抽象:只包含方法、属性、事件和索引器的签名
- 多继承:类可以实现多个接口
- 解耦:分离定义与实现,降低耦合度
- 多态:实现接口的不同类可以以统一方式处理
### 3.1 定义接口
```c#
public interface ILogger
{
// 方法签名
void Log(string message);
// 属性签名
string LogLevel { get; set; }
// 事件签名
event Action<string> OnLogged;
// 默认实现(C# 8.0+)
void LogError(string error)
{
Log($"[ERROR] {error}");
OnLogged?.Invoke(error);
}
}
```
### 3.2 实现接口
```c#
public class FileLogger : ILogger
{
private string _logLevel = "INFO";
public string LogLevel
{
get => _logLevel;
set => _logLevel = value;
}
public event Action<string> OnLogged;
public void Log(string message)
{
File.AppendAllText("log.txt", $"[{LogLevel}] {DateTime.Now}: {message}\n");
OnLogged?.Invoke(message);
}
// 可以选择重写默认实现
public void LogError(string error)
{
Log($"[CRITICAL] {error}");
}
}
```
### 3.3 显式接口实现
解决多个接口有相同成员名的问题
```c#
public interface IDatabase
{
void Connect();
}
public interface IWebService
{
void Connect();
}
public class DataService : IDatabase, IWebService
{
// 显式实现IDatabase.Connect
void IDatabase.Connect()
{
Console.WriteLine("Connecting to database...");
}
// 显式实现IWebService.Connect
void IWebService.Connect()
{
Console.WriteLine("Connecting to web service...");
}
// 普通方法
public void Connect()
{
Console.WriteLine("General connection...");
}
}
// 使用
var service = new DataService();
service.Connect(); // 调用普通方法
((IDatabase)service).Connect(); // 调用IDatabase实现
((IWebService)service).Connect(); // 调用IWebService实现
```
### 3.4 接口继承
```c#
public interface IShape
{
double CalculateArea();
}
public interface IDrawable : IShape
{
void Draw();
}
public class Circle : IDrawable
{
public double Radius { get; set; }
public double CalculateArea()
{
return Math.PI * Radius * Radius;
}
public void Draw()
{
}
}
```
### 3.5 默认接口方法(C# 8.0+)
```c#
public interface IOrder
{
decimal Amount { get; }
DateTime Date { get; }
// 默认实现
string GetOrderInfo()
{
return $"Order on {Date:d} for {Amount:C}";
}
}
public class OnlineOrder : IOrder
{
public decimal Amount { get; set; }
public DateTime Date { get; set; }
// 可以选择不实现GetOrderInfo
}
// 使用
IOrder order = new OnlineOrder { Amount = 100.50m, Date = DateTime.Now };
Console.WriteLine(order.GetOrderInfo()); // 使用接口默认实现
```
## 4.抽象类
抽象类是C#中一种特殊的类,它不能被实例化,只能被继承。
1.不能被实例化:只能作为基类
2.可以包含抽象成员:没有实现的成员
3.可以包含具体实现:非抽象成员可以有实现
4.介于接口和普通类之间:比接口更具体,比普通类更抽象
### 4.1 定义抽象类
```c#
public abstract class Shape
{
// 抽象方法(没有实现)
public abstract double CalculateArea();
// 普通方法(有实现)
public void Display()
{
Console.WriteLine($"Area: {CalculateArea()}");
}
// 抽象属性
public abstract string Name { get; }
// 普通属性
public string Color { get; set; } = "Black";
}
```
### 4.2 继承抽象类
```c#
public class Circle : Shape
{
public double Radius { get; set; }
// 必须实现抽象成员
public override double CalculateArea()
{
return Math.PI * Radius * Radius;
}
public override string Name => "Circle";
// 可以选择重写普通方法
public override void Display()
{
Console.WriteLine($"Circle with radius {Radius} has area {CalculateArea():F2}");
}
}
```
### 4.3 抽象类与构造方法
```c#
public abstract class Animal
{
public string Species { get; }
// 抽象类可以有构造方法
protected Animal(string species)
{
Species = species;
}
public abstract void MakeSound();
}
public class Dog : Animal
{
public Dog() : base("Canine") { }
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}
```
### 4.4 抽象类与密封方法
```c#
public abstract class Vehicle
{
public abstract void StartEngine();
// 密封方法(在派生类中不能被重写)
public sealed void StopEngine()
{
Console.WriteLine("Engine stopped");
}
}
public class Car : Vehicle
{
public override void StartEngine()
{
Console.WriteLine("Car engine started");
}
// 不能重写StopEngine方法
}
```
### 4.5 抽象类与虚方法
```c#
public abstract class Database
{
// 抽象方法(必须被重写)
public abstract void Connect();
// 虚方法(可以被重写)
public virtual void Disconnect()
{
Console.WriteLine("Disconnected from database");
}
}
public class SqlDatabase : Database
{
public override void Connect()
{
Console.WriteLine("Connected to SQL Server");
}
// 可以选择重写虚方法
public override void Disconnect()
{
Console.WriteLine("SQL Server connection closed");
base.Disconnect(); // 调用基类实现
}
}
```
### 4.6 抽象类与接口的比较
|特性 |抽象类| 接口|
|-|-|-|
|实例化| 不能 |不能|
|默认实现| 可以有 |C# 8.0+可以有默认实现|
|字段 |可以包含实例字段| 不能|
|构造方法 |可以有| 不能|
|访问修饰符 |可以控制成员访问级别 |默认为public|
|多继承| 不支持 |支持|
|版本控制 |添加新方法不影响现有子类 |添加新成员会破坏现有实现|
## 5.委托
### 5.1 描述
- 类型安全的函数指针:委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用
- 回调机制:允许将方法作为参数传递
- 多播能力:一个委托可以引用多个方法
### 5.2 委托的声明与使用
```c#
using static TestDelegateDemo;
public class Program
{
public static void Main(string[] args)
{
TestDelegateDemo testDelegateDemo = new TestDelegateDemo();
testDelegateDemo.del += new MyDelegate(ShowMessage);
testDelegateDemo.del += new MyDelegate(ShowMessage2);
testDelegateDemo.del += new MyDelegate(ShowMessage3);
// 也可进行删除
// testDelegateDemo.del -= new MyDelegate(ShowMessage2);
// 匿名方法
testDelegateDemo.del += delegate (string msg)
{
Console.WriteLine("匿名方法:" + msg);
};
// Lambda表达式
testDelegateDemo.del += (msg) =>
{
Console.WriteLine("Lambda表达式:" + msg);
};
testDelegateDemo.ShowAllMessage();
// 直接调用
//testDelegateDemo.del?.Invoke("Hello, World!");
}
public static void ShowMessage(string msg)
{
Console.WriteLine("sm1:"+msg);
}
public static void ShowMessage2(string msg)
{
Console.WriteLine("sm2:" + msg);
}
public static void ShowMessage3(string msg)
{
Console.WriteLine("sm3:" + msg);
}
}
public class TestDelegateDemo
{
public delegate void MyDelegate(string message);
public MyDelegate? del;
public void ShowAllMessage()
{
del?.Invoke("Hello, World!");
}
}
```
### 5.3 内置委托类型
C# 提供了几种内置的通用委托类型,避免重复声明:
- Action:无返回值的方法(最多16个参数)
- Func:有返回值的方法(最多16个参数)
- Predicate:返回bool的方法(1个参数)
```c#
// 使用Action
Action<string> action = msg => Console.WriteLine(msg);
action("Hello Action!");
// 使用Func
Func<int, int, int> add = (a, b) => a + b;
int result = add(3, 5); // 8
// 使用Predicate
Predicate<int> isEven = num => num % 2 == 0;
bool even = isEven(4); // true
```
## 6.事件
### 6.1 描述
- 基于委托的发布-订阅模型:事件是委托的一种特殊形式,用于实现观察者模式
- 封装性:事件限制了外部对委托的直接访问
- 安全机制:防止外部直接调用或重置委托
### 6.2 标准事件模式
完整实现:
```c#
public class Program
{
public static void Main(string[] args)
{
var monitor = new TemperatureMonitor();
monitor.TemperatureChanged += (sender, e) =>
{
Console.WriteLine($"温度变化: {e.OldTemperature}°C -> {e.NewTemperature}°C");
};
monitor.CurrentTemperature = 10.0f;
monitor.CurrentTemperature = 36.0f;
}
}
/// <summary>
/// 气温监听器
/// </summary>
public class TemperatureMonitor
{
public delegate void TemperatureChangedHandler(object sender, TemperatureEventArgs e);
public event TemperatureChangedHandler? TemperatureChanged;
private float _currentTemp;
public float CurrentTemperature
{
get => _currentTemp;
set
{
if (_currentTemp != value)
{
float oldTemp = _currentTemp;
_currentTemp = value;
//触发事件
OnTemperatureChanged(oldTemp, _currentTemp);
}
}
}
protected virtual void OnTemperatureChanged(float oldTemp, float newTemp)
{
TemperatureChanged?.Invoke(this, new TemperatureEventArgs(oldTemp, newTemp));
}
}
public class TemperatureEventArgs : EventArgs
{
public float OldTemperature { get; }
public float NewTemperature { get; }
public TemperatureEventArgs(float oldTemp, float newTemp)
{
OldTemperature = oldTemp;
NewTemperature = newTemp;
}
}
```
简单实现
```c#
public class Program
{
public static void Main(string[] args)
{
var monitor = new TemperatureMonitor();
monitor.TemperatureChanged += (sender, e) =>
{
Console.WriteLine($"温度变化: {e.OldTemperature}°C -> {e.NewTemperature}°C");
};
monitor.CurrentTemperature = 10.0f;
monitor.CurrentTemperature = 36.0f;
}
}
/// <summary>
/// 气温监听器
/// </summary>
public class TemperatureMonitor
{
public event EventHandler<TemperatureEventArgs>? TemperatureChanged;
private float _currentTemp;
public float CurrentTemperature
{
get => _currentTemp;
set
{
if (_currentTemp != value)
{
float oldTemp = _currentTemp;
_currentTemp = value;
//触发事件
OnTemperatureChanged(oldTemp, _currentTemp);
}
}
}
protected virtual void OnTemperatureChanged(float oldTemp, float newTemp)
{
TemperatureChanged?.Invoke(this, new TemperatureEventArgs(oldTemp, newTemp));
}
}
public class TemperatureEventArgs : EventArgs
{
public float OldTemperature { get; }
public float NewTemperature { get; }
public TemperatureEventArgs(float oldTemp, float newTemp)
{
OldTemperature = oldTemp;
NewTemperature = newTemp;
}
}
```
### 6.3 事件与委托的关键区别
|特性|委托 |事件|
|-|-|-|
|访问控制| 可被外部直接调用和赋值 |只能在声明类内部触发|
|多播能力 |支持| 支持|
|外部订阅/取消 |可以 |只能通过+=/-=操作|
|用途 |通用回调机制| 实现观察者模式|
|安全性 |低(可能被外部重置)| 高(封装了委托)|
## 7.结构体
结构体(struct)是C#中的一种值类型,与类(class)这种引用类型有着本质区别。
### 7.1 结构体基本概念
定义语法
```c#
public struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
public void Move(int deltaX, int deltaY)
{
X += deltaX;
Y += deltaY;
}
}
```
核心特性:
- 值类型:存储在栈上(通常),直接包含数据
- 默认构造函数:编译器自动生成无参构造函数,不能自定义
- 继承限制:不能继承其他结构体或类,只能实现接口
- 不可为null:除非声明为可空类型(Nullable<Point>或Point?)
- 隐式密封:结构体隐式是密封的(sealed)
### 7.2 结构体与类的区别
|特性 |结构体| 类|
|-|-|-|
|类型 |值类型 |引用类型|
|存储位置 |栈(通常) |堆|
|继承 |只能实现接口 |支持单继承和多接口实现|
|默认构造函数 |自动生成,不能自定义| 可以自定义|
|析构函数 |不支持| 支持|
|可为null |必须显式声明可空| 默认可为null|
|赋值行为| 复制整个值|复制引用|
|大小限制 |建议小于16字节| 无限制|
### 7.3 结构体的构造函数
```c#
public struct Rectangle
{
public double Width;
public double Height;
// 带参数的构造函数
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
// 编译错误:不能定义无参构造函数
// public Rectangle() { }
// 计算属性
public double Area => Width * Height;
}
// 使用
var rect1 = new Rectangle(10, 20); // 使用构造函数
var rect2 = new Rectangle(); // 使用默认构造函数,数值类型初始化为0
```
### 7.4 结构体的方法
```c#
public struct Vector3D
{
public double X, Y, Z;
public double Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z);
public override string ToString() => $"({X}, {Y}, {Z})";
public static Vector3D operator +(Vector3D a, Vector3D b) =>
new Vector3D { X = a.X + b.X, Y = a.Y + b.Y, Z = a.Z + b.Z };
}
```
### 7.5 只读结构体(C# 7.2+)
```c#
public readonly struct ImmutablePoint
{
public readonly int X;
public readonly int Y;
public ImmutablePoint(int x, int y)
{
X = x;
Y = y;
}
public double Distance => Math.Sqrt(X * X + Y * Y);
// 编译错误:不能修改只读结构体的字段
// public void Move(int dx, int dy) { X += dx; Y += dy; }
}
// 使用
var point = new ImmutablePoint(3, 4);
Console.WriteLine(point.Distance);
```
### 7.6 ref结构体(C# 7.2+)
```c#
public ref struct StackOnlyStruct
{
public int Value;
public void Increment() => Value++;
}
// 使用
var stackOnly = new StackOnlyStruct { Value = 10 };
stackOnly.Increment();
// 不能将ref结构体装箱或放入堆中
// object obj = stackOnly; // 编译错误
// List<StackOnlyStruct> list; // 编译错误
```
## 8.记录
记录(Record)是C# 9.0引入的一种新的引用类型,主要用于简化不可变数据模型的创建。
### 8.1 基本概念
- 不可变性:默认属性为init-only
- 值语义相等:基于内容而非引用比较
- 简洁语法:减少样板代码
- 非破坏性修改:with表达式创建修改后的副本
- ToString格式化:自动生成友好的ToString实现
```c#
// 位置记录(简洁语法)
public record Person(string FirstName, string LastName);
// 标准记录语法
public record Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
}
```
### 8.2 记录类型与类的区别
|特性 |记录类型| 类|
|-|-|-|
|相等性比较 |基于内容(值语义) |基于引用(默认)|
|不可变性 |默认| 需要手动实现|
|复制修改 |内置with表达式支持| 需要手动实现|
|ToString实现 |自动生成友好格式| 默认返回类型名称|
|继承 |支持 |支持|
|解构 |内置支持| 需要手动实现|
### 8.3 记录类型的主要特性
1).位置记录
```c#
public record Point(double X, double Y);
// 使用
var p1 = new Point(1.0, 2.0);
var (x, y) = p1; // 解构
Console.WriteLine(p1); // 输出: Point { X = 1, Y = 2 }
```
2).非破坏性修改(with表达式)
```c#
var original = new Point(1.0, 2.0);
var modified = original with { X = 3.0 };
Console.WriteLine(original); // Point { X = 1, Y = 2 }
Console.WriteLine(modified); // Point { X = 3, Y = 2 }
```
3).值语义相等
```c#
var p1 = new Point(1.0, 2.0);
var p2 = new Point(1.0, 2.0);
Console.WriteLine(p1 == p2); // True
Console.WriteLine(ReferenceEquals(p1, p2)); // False
```
4).记录继承
```c#
public record Person(string FirstName, string LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
// 使用
var student = new Student("John", "Doe", 3);
Console.WriteLine(student); // Student { FirstName = John, LastName = Doe, Grade = 3 }
```
## 9.元组
元组是C#中的一种轻量级数据结构,用于临时组合多个值而无需创建专门的类或结构体。
```c#
// 未命名元组(Item1, Item2...)
var unnamedTuple = ("John", 30);
// 命名元组
var namedTuple = (Name: "John", Age: 30);
// 访问元素
Console.WriteLine(unnamedTuple.Item1); // "John"
Console.WriteLine(namedTuple.Age); // 30
// 显式声明元组类型
(string, int) person1 = ("Alice", 25);
(string Name, int Age) person2 = ("Bob", 30);
// 作为方法返回类型
public (string, int) GetPerson() => ("Charlie", 35);
```
## 10.枚举
### 10.1基本使用
枚举(Enumeration)是C#中的一种值类型,用于定义一组命名常量。
```c#
// 基本枚举
public enum Weekday
{
Monday, // 默认值0
Tuesday, // 1
Wednesday, // 2
Thursday, // 3
Friday, // 4
Saturday, // 5
Sunday // 6
}
// 带显式值的枚举
public enum StatusCode : int
{
Success = 200,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
ServerError = 500
}
// ==========================
// 声明
public enum Color { Red, Green, Blue }
// 使用
Color favorite = Color.Blue;
// 比较
if (favorite == Color.Blue)
{
Console.WriteLine("蓝色");
}
```
### 10.2 标志枚举(Flags)
```c#
[Flags]
public enum Permissions
{
None = 0, // 0b_0000
Read = 1, // 0b_0001
Write = 2, // 0b_0010
Execute = 4, // 0b_0100
Delete = 8, // 0b_1000
All = Read | Write | Execute | Delete // 0b_1111 (15)
}
// 组合权限
Permissions userPermissions = Permissions.Read | Permissions.Write;
// 检查权限
if (userPermissions.HasFlag(Permissions.Read))
{
Console.WriteLine("拥有读取权限");
}
// 添加权限
userPermissions |= Permissions.Execute;
// 移除权限
userPermissions &= ~Permissions.Write;
// 检查多个权限
if ((userPermissions & (Permissions.Read | Permissions.Write)) == (Permissions.Read | Permissions.Write))
{
Console.WriteLine("拥有读取和写入权限");
}
```
### 10.3 枚举描述特性
```c#
public enum LogLevel
{
[Description("调试信息")]
Debug,
[Description("一般信息")]
Info,
[Description("警告信息")]
Warning,
[Description("错误信息")]
Error
}
public static string GetDescription(this Enum value)
{
var field = value.GetType().GetField(value.ToString());
var attribute = field?.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
return attribute?.Description ?? value.ToString();
}
// 使用
Console.WriteLine(LogLevel.Warning.GetDescription()); // "警告信息"
```
### 10.4 枚举遍历
```c#
foreach (Weekday day in Enum.GetValues(typeof(Weekday)))
{
Console.WriteLine($"{day} = {(int)day}");
}
// 获取所有枚举名称
string[] colorNames = Enum.GetNames(typeof(Color));
```