一.c# 初级

2026-05-12 08:00 401 阅读

一.c# 基础阶段

1.程序结构

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';

复合值类型

// 结构体示例
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;

复合引用类型

// 类示例
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);

记录类型

// 记录类 (不可变引用类型)
public record Product(string Name, decimal Price);

// 记录结构 (不可变值类型)
public readonly record struct Point(int X, int Y);

3.3 特殊类型

可为空值类型

int? nullableInt = null;           // Nullable<int>
double? nullableDouble = 3.14;     // Nullable<double>
bool? nullableBool = null;         // Nullable<bool>

// 安全访问
int value = nullableInt ?? -1;     // 如果null则返回-1

指针类型

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 类型转换

隐式转换 (自动)

int i = 10;
long l = i;     // 小范围转大范围

显式转换 (强制)

double d = 3.14;
int i = (int)d; // 大范围转小范围

方法转换

// Parse/TryParse
int num = int.Parse("123");
bool success = int.TryParse("abc", out int result);

// Convert类
decimal dec = Convert.ToDecimal(3.14);

类型检查与转换

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 变量基础概念

变量定义

  • 变量是存储数据的命名内存位置
  • 必须先声明后使用
  • 包含:变量名、数据类型和值

变量声明语法

数据类型 变量名;          // 声明
数据类型 变量名 = 初始值;  // 声明并初始化

4.2 变量类型分类

按数据类型分类

类型 示例 说明
值类型变量 int age = 25; 直接存储数据
引用类型变量 string name = "Tom"; 存储数据引用
指针类型变量 int* ptr; 存储内存地址(unsafe上下文)

按作用域分类

类型 声明位置 生命周期
局部变量 方法/代码块内 所在代码块执行期间
字段变量 类/结构体内 所属对象存在期间
静态变量 类中用static声明 程序运行期间
参数变量 方法参数列表 方法执行期间

4.3 变量/常量声明

基本变量声明

int count;                  // 声明未初始化
double price = 19.99;        // 声明并初始化
char grade = 'A';           // 字符类型
bool isCompleted = false;   // 布尔类型

类型推断(var)

var message = "Hello";      // 编译为string
var number = 42;            // 编译为int
var list = new List<int>();  // 编译为List<int>

// var必须初始化,不能用于字段声明
// var不能用于方法参数和返回类型

常量声明

const double PI = 3.14159;
const int MaxUsers = 100;

// 常量必须在声明时初始化
// 常量默认为静态(static)

元组变量

// 命名元组
var person = (Name: "Alice", Age: 25);
Console.WriteLine(person.Name);

// 解构元组
(string name, int age) = person;

4.4 变量作用域规则

局部变量作用域

void Method()
{
    int x = 10;  // 作用域开始

    if (true)
    {
        int y = 20;  // 仅在此块内有效
        x = 30;      // 可以访问外部变量
    }

    // y = 40;  // 错误!y不可访问
}  // 作用域结束,x被销毁

字段变量作用域

class MyClass
{
    private int _field;  // 类级作用域

    void Method()
    {
        _field = 10;     // 可在类内任何方法访问
    }
}

变量隐藏

int x = 10;

if (true)
{
    int x = 20;  // 隐藏外部x
    Console.WriteLine(x);  // 20
}

Console.WriteLine(x);  // 10

4.5 特殊变量类型

可为空变量

int? nullableInt = null;   // Nullable<int>
double? price = null;

// 安全访问
int value = nullableInt ?? -1;  // null合并运算符

固定大小缓冲区

unsafe struct FixedBuffer
{
    public fixed char buffer[128];  // 固定大小数组
}

范围变量

范围变量(Range Variable)是LINQ查询表达式中的特殊变量,它表示数据源中的单个元素。范围变量是LINQ查询中的"临时代表",代表数据集合中的单个元素,只在当前查询表达式中有效,类似于foreach循环中的迭代变量。

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 表达式

基本表达式

42                  // 字面量表达式
a                   // 变量表达式
a + b               // 算术表达式
a > b               // 关系表达式

复合表达式

(a + b) * c         // 组合算术表达式
(a > b) && (c < d)  // 组合逻辑表达式

Lambda表达式

x => x * x          // 单参数Lambda
() => Console.WriteLine("Hello") // 无参数Lambda

查询表达式

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检查简化​​:

// 传统方式
if (obj != null) { var name = obj.Name; }

// 使用?.运算符
var name = obj?.Name;

3.类型转换最佳实践:

// 安全转换(推荐)
string s = obj as string;
if (s != null) { ... }

// 强制转换(确定类型时使用)
string s = (string)obj;

4.​​模式匹配(C# 7.0+)​​:

if (obj is string str) {
    Console.WriteLine(str.Length);
}

5.范围运算符(C# 8.0+)​​:

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++(后缀)有区别:

int a = 1;
int b = a++; // b=1, a=2
int c = ++a; // c=3, a=3

3.浮点数比较应使用容差而非直接==:

// 不推荐
if (d1 == d2) {...}

// 推荐
if (Math.Abs(d1 - d2) < 0.0001) {...}

4.运算符重载示例:

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

if (条件表达式)
{
    // 条件为真时执行的代码
}

if (条件表达式)
{
    // 条件为真时执行
}
else
{
    // 条件为假时执行
}

if (条件1)
{
    // 条件1为真时执行
}
else if (条件2)
{
    // 条件2为真时执行
}
else
{
    // 所有条件为假时执行
}

switch

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

for (初始化; 条件; 迭代)
{
    // 循环体
}

// 示例
for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i);
}

while

while (条件表达式)
{
    // 循环体
}

// 示例
int i = 0;
while (i < 10)
{
    Console.WriteLine(i);
    i++;
}

do-while

do
{
    // 循环体(至少执行一次)
} while (条件表达式);

// 示例​​
int i = 0;
do
{
    Console.WriteLine(i);
    i++;
} while (i < 10);

foreach

foreach (类型 变量 in 集合)
{
    // 循环体
}

// 示例
string[] names = { "Alice", "Bob", "Charlie" };
foreach (string name in names)
{
    Console.WriteLine(name);
}

6.3 跳转语句

break

立即终止当前循环或switch语句

for (int i = 0; i < 10; i++)
{
    if (i == 5)
        break; // 当i=5时退出循环
    Console.WriteLine(i);
}

continue 跳过当前循环迭代,继续下一次迭代

for (int i = 0; i < 10; i++)
{
    if (i % 2 == 0)
        continue; // 跳过偶数
    Console.WriteLine(i);
}

return 立即退出当前方法,并可返回一个值

int Add(int a, int b)
{
    return a + b; // 返回计算结果
}

goto

for (int i = 0; i < 10; i++)
{
    if (i == 5)
        goto EndLoop; // 跳转到标签处
    Console.WriteLine(i);
}
EndLoop:
Console.WriteLine("循环结束");

6.4 特殊控制结构

try-catch-finally

try
{
    // 可能抛出异常的代码
}
catch (特定异常类型 ex)
{
    // 处理特定异常
}
catch (Exception ex)
{
    // 处理所有其他异常
}
finally
{
    // 无论是否发生异常都会执行的代码
}

using

using (var resource = new DisposableResource())
{
    // 使用资源
    // 离开作用域时自动调用Dispose(),在处理IO流相关操作时用到
    }

yield return

IEnumerable<int> GetNumbers()
{
    for (int i = 0; i < 10; i++)
    {
        yield return i; // 延迟生成值
    }
}

6.5 C# 8.0+ 新特性

switch

var result = operation switch
{
    "+" => a + b,
    "-" => a - b,
    "*" => a * b,
    "/" => a / b,
    _ => throw new InvalidOperationException("未知运算符")
};

模式匹配增强

if (obj is string { Length: >5 } s)
{
    Console.WriteLine($"长字符串: {s}");
}

异步流

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 数组声明与初始化

基本语法

// 方式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};

多维数组

// 二维数组(矩形数组)
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)

锯齿数组

// 声明锯齿数组
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 数组操作

基本操作

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);
}

数组复制

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);

数组排序与搜索

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}");
}

数组转换

// 类型转换
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 数组高级

数组协变(仅适用于引用类型)

object[] objArr = new string[10]; // 合法
// objArr[0] = 5; // 运行时抛出ArrayTypeMismatchException

数组初始化器

// 多维数组初始化
int[,] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};

// 锯齿数组初始化
int[][] jagged = {
    new int[] {1, 2},
    new int[] {3, 4, 5}
};

数组与Span

Span:内存中连续的数据

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)

unsafe {
    int[] arr = {1, 2, 3};
    fixed (int* ptr = arr) {
        for (int i = 0; i < arr.Length; i++) {
            Console.WriteLine(*(ptr + i));
        }
    }
}

7.5 数组实用技巧

数组比较

int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};

// 比较引用
bool sameRef = arr1 == arr2; // false

// 比较内容
bool sameContent = arr1.SequenceEqual(arr2); // true

数组填充

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]

数组反转

int[] arr = {1, 2, 3, 4};
Array.Reverse(arr); // [4,3,2,1]

// 部分反转
Array.Reverse(arr, 1, 2); // [4,2,3,1]

数组清空

int[] arr = {1, 2, 3};
Array.Clear(arr, 0, arr.Length); // 所有元素设为0

8.集合

8.1 集合核心概念

集合与数组的区别

特性 数组 集合
大小 固定 动态可变
功能 基础操作 丰富的数据操作方法
内存 连续存储 可能非连续
性能 访问快(O(1)) 不同集合性能差异大
类型安全 同类型元素 泛型集合保证类型安全

集合分类体系

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)

性能优化

// 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)时扩容 核心操作

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}");
}

碰撞与性能优化

// 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实现
  • ​​​​集合运算​​:支持并/交/差集
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)
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

Queue<string> queue = new Queue<string>();

// 入队
queue.Enqueue("First");
queue.Enqueue("Second");

// 出队
string item = queue.Dequeue(); // "First"

// 查看队首
string peek = queue.Peek(); // "Second"

栈Stack

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

// 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);

同步包装器

// 创建线程安全集合
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 性能优化

预分配容量​​:减少扩容操作

new List<int>(1000);
new Dictionary<string,int>(5000);

避免装箱拆箱​​:使用泛型集合

// 错误:ArrayList导致装箱
ArrayList badList = new ArrayList();
badList.Add(1); // 装箱

// 正确:List<T>避免装箱
List<int> goodList = new List<int>();
goodList.Add(1); // 无装箱

批量操作​​:减少方法调用开销

// 优于多次Add
list.AddRange(items);

​​LINQ延迟执行​​:及时物化查询

// 立即执行
var result = source.Where(x => x > 0).ToList();

9.字符串

9.1 字符串基础

9.1.1 字符串特性

  • 不可变性(Immutable)​​:字符串一旦创建就不能修改,所有"修改"操作都返回新字符串
  • 引用类型​​:但具有值类型的某些特性
  • ​​Unicode编码​​:支持多语言字符
  • ​​字符串池(String Interning)​​:CLR对字面量字符串的优化机制

9.1.2 字符串创建方式

// 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 基本操作

// 长度获取
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 字符串比较

// 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 字符串查找

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 字符串修改

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 复合格式化

string.Format("Name: {0}, Age: {1}", "Alice", 25);
// "Name: Alice, Age: 25"

9.3.2 字符串插值(C# 6.0+)

string name = "Alice";
int age = 25;
string result = $"Name: {name}, Age: {age}";
// "Name: Alice, Age: 25"

9.3.3 数值格式化

// 数字格式化
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)

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)

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 逐字字符串(@)与转义字符

// 普通字符串
string path1 = "C:\\Windows\\System32"; // 需要转义

// 逐字字符串
string path2 = @"C:\Windows\System32"; // 不需要转义

// 多行字符串
string multiLine = @"Line 1
Line 2
Line 3";

9.5 字符串编码与转换

9.5.1 编码转换

// 字符串转字节数组
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编码

// 编码
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes("Hello"));

// 解码
string original = Encoding.UTF8.GetString(Convert.FromBase64String(base64));

9.6 字符串性能优化

9.6.1 避免不必要的字符串操作

// 不好:创建多个临时字符串
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 比较优化

// 不好:区分大小写的比较
if (input.ToLower() == "admin") { ... }

// 好:使用比较选项
if (input.Equals("admin", StringComparison.OrdinalIgnoreCase)) { ... }

9.6.3 字符串分割优化

// 不好:多次分割
string[] parts1 = csv.Split(',');
string[] parts2 = csv.Split(';');

// 好:一次性分割
char[] separators = { ',', ';' };
string[] parts = csv.Split(separators);

9.7 正则表达式

9.7.1 基本用法

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 常用模式

// 电子邮件验证
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 字符串安全

敏感信息处理

// 使用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 基本输入输出 输出文本

Console.Write("Hello");       // 不换行输出
Console.WriteLine("World");    // 输出后换行

读取输入

string input = Console.ReadLine();  // 读取一行输入
int key = Console.Read();           // 读取单个字符(返回ASCII码)
ConsoleKeyInfo keyInfo = Console.ReadKey(); // 读取按键信息

10.2 格式化输出

10.2.1 复合格式化

string name = "Alice";
int age = 25;
Console.WriteLine("Name: {0}, Age: {1}", name, age);

10.2.2 字符串插值(C# 6.0+)

Console.WriteLine($"Name: {name}, Age: {age}");

10.2.3 数值格式化

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 颜色属性

Console.ForegroundColor = ConsoleColor.Red;    // 前景色(文本)
Console.BackgroundColor = ConsoleColor.White;  // 背景色
Console.ResetColor(); // 重置为默认颜色   

10.3.2 颜色示例

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("警告信息");
Console.ResetColor();

10.4 控制台窗口控制

10.4.1 窗口属性 可能只在windows生效

Console.WindowWidth = 80;       // 设置窗口宽度
Console.WindowHeight = 30;      // 设置窗口高度
Console.BufferWidth = 100;      // 设置缓冲区宽度
Console.BufferHeight = 1000;    // 设置缓冲区高度
Console.Title = "我的控制台";    // 设置窗口标题

10.4.2 光标控制

Console.CursorVisible = false;  // 隐藏光标
Console.SetCursorPosition(10, 5); // 设置光标位置(列,行)
Console.CursorLeft = 20;        // 设置光标列位置
Console.CursorTop = 10;        // 设置光标行位置

10.5 高级功能

10.5.1 控制台铃声

Console.Beep();                 // 默认频率和时长
Console.Beep(800, 200);         // 频率(Hz), 时长(ms)

10.5.2 编码设置

Console.OutputEncoding = Encoding.UTF8;  // 设置输出编码
Console.InputEncoding = Encoding.UTF8;   // 设置输入编码

10.5.3 清屏与进度显示

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 块**

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

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 语句

// 重新抛出当前异常
catch (Exception ex)
{
    Console.WriteLine("记录错误");
    throw; // 保留原始调用栈
}

// 抛出新异常
if (value < 0)
    throw new ArgumentException("值不能为负");

11.3 异常处理高级特性

11.3.1 异常筛选器 (C# 6.0+)

try { /* ... */ }
catch (Exception ex) when (ex.Message.Contains("特定错误"))
{
    // 仅当条件满足时捕获
}

11.3.2 自定义异常

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 异常数据字典

try { /* ... */ }
catch (Exception ex)
{
    ex.Data.Add("Timestamp", DateTime.Now);
    ex.Data.Add("User", "Admin");
    throw;
}

11.4 异常处理与资源管理

11.4.1 using 语句

using (var resource = new DisposableResource())
{
    // 自动调用Dispose(),即使抛出异常
}

11.4.2 模式匹配 (C# 7.0+)

try { /* ... */ }
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
    Console.WriteLine("文件访问错误");
}

二.面向对象编程

1.类与对象

1.1 类和对象的基本概念

类 (Class)

  • 类是创建对象的蓝图或模板
  • 定义了对象的属性和行为
  • 是面向对象编程的基本构建块

对象 (Object)

  • 对象是类的实例
  • 每个对象都有自己的状态(属性值)和行为(方法)
  • 对象通过new关键字创建
// 定义一个类
public class Person
{
    // 类的成员
}

// 创建对象
Person person1 = new Person();

1.2 类的成员

1.2.1 字段 (Fields)

  • 存储类或对象的数据
  • 通常设为私有(private),通过属性访问
private string _name;
private int _age;

1.2.2 属性 (Properties)

  • 提供对字段的安全访问
  • 可以包含get和set访问器 
private string _name;
public string Name
{
    get { return _name; }
    set { _name= value; }
}

// 自动属性(C# 3.0+)
public int Age { get; set; }

1.2.3 方法 (Methods)

  • 定义类的行为
  • 可以接受参数并返回值
public void SayHello()
{
    Console.WriteLine($"Hello, my name is {Name}");
}

public int CalculateAgeInMonths()
{
    return Age * 12;
}

1.2.4 构造函数 (Constructors)

  • 用于初始化对象
  • 与类同名,没有返回类型
  • 可以重载
public Person()
{
    // 默认构造函数
}

public Person(string name, int age)
{
    Name = name;
    Age = age;
}

1.3 文档注释​​

为公共方法,属性添加注释,该注释能辅助编写代码时鼠标放上去查看解释

/// <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 静态成员

  • 属于类而不是对象
  • 通过类名访问,而不是对象实例
  • 常用于工具类或共享数据
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的,尝试继承会编译错误
public static class MathUtility
{
    public static double PI = 3.14159;
}

// 使用静态成员
double pi = MathUtility.PI;

1.7 静态构造函数

  • 在首次访问类时自动执行
  • 每个应用程序域只执行一次
  • 没有访问修饰符和参数
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 析构函数/终结器

  • 在对象销毁前执行清理操作
  • 不能手动调用,由垃圾回收器自动调用
~Person()
{
    // 清理代码
}

现代对象销毁设计

public class Resource : IDisposable
{
    public void Dispose() 
    {
        // 确定性释放资源
    }
}

// 使用示例
using (var res = new Resource()) 
{
    // 自动调用Dispose()
}

1.9 ref、out

1.9.1 值传递 vs 引用传递​ ​​默认行为​​:C# 方法参数默认是​​值传递​​(传递副本)

void Modify(int x) { x = 100; }

int num = 10;
Modify(num);  // num 仍然是10

1.9.2 ref 关键字​ 实现​​引用传递​​,方法内修改会影响原始变量,调用前​​必须初始化​​变量,方法声明和调用时都要加 ref。

void ModifyRef(ref int x) { x = 100; }

int num = 10;
ModifyRef(ref num);  // num 变为100

1.9.3 out 关键字​ 用于从方法返回多个值(类似引用传递),调用前​​无需初始化​​变量,方法内​​必须赋值​​给out参数,方法声明和调用时都要加 out。

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 运算符重载

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# 中的一种特殊成员,它允许类的实例像数组一样通过索引来访问。索引器类似于属性,但使用索引参数而不是属性名。

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 链式构造和指代当前

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 类拓展

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 部分类

将一个类分为两个文件编写,编译后为一个类

// File1.cs
public partial class MyClass
{
    public void Method1() { }
}

// File2.cs
public partial class MyClass
{
    public void Method2() { }
}

1.13 对象初始化器

//  Name 和 Age 为公开可写的属性
Person person = new Person 
{
    Name = "John",
    Age = 30
};

1.14 只读属性和只读字段

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 封装

两个核心思想:

  • ​​数据隐藏​​:将对象的内部状态(数据)隐藏起来,不允许外部直接访问
  • ​​行为暴露​​:通过公共方法(接口)提供对数据的受控访问

简单的封装示例:

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"关系​​:子类是父类的一种特殊类型

继承的基本语法

// 基类(父类)
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)不会被继承

构造函数继承

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;
    }
}

方法重写(虚方法)

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关键字)

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"

只有重写才有多态效果,方法重叠和隐藏方法都不行

密封类和密封方法

public sealed class FinalClass  // sealed关键字表示不能被继承
{
    // 类成员
}

public class BaseClass
{
    public virtual void Method()
    {
        // 可重写的方法
    }
}

public class DerivedClass : BaseClass
{
    public sealed override void Method()  // 密封方法,不能再被重写
    {
        // 方法实现
    }
}

多继承与接口 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 多态

编译时多态(方法重载)

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 定义接口

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 实现接口

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 显式接口实现

解决多个接口有相同成员名的问题

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 接口继承

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+)

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 定义抽象类

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 继承抽象类

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 抽象类与构造方法

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 抽象类与密封方法

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 抽象类与虚方法

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 委托的声明与使用

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个参数)
// 使用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 标准事件模式

完整实现:

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;
    }
}

简单实现

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 结构体基本概念

定义语法

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?)
  • ​​隐式密封​​:结构体隐式是密封的(sealed)

7.2 结构体与类的区别

特性 结构体
类型 值类型 引用类型
存储位置 栈(通常)
继承 只能实现接口 支持单继承和多接口实现
默认构造函数 自动生成,不能自定义 可以自定义
析构函数 不支持 支持
可为null 必须显式声明可空 默认可为null
赋值行为 复制整个值 复制引用
大小限制 建议小于16字节 无限制

7.3 结构体的构造函数

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 结构体的方法

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+)

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+)

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实现
// 位置记录(简洁语法)
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).位置记录

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表达式)

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).值语义相等

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).记录继承

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#中的一种轻量级数据结构,用于临时组合多个值而无需创建专门的类或结构体。

// 未命名元组(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#中的一种值类型,用于定义一组命名常量。

// 基本枚举
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)

[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 枚举描述特性

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 枚举遍历

foreach (Weekday day in Enum.GetValues(typeof(Weekday)))
{
    Console.WriteLine($"{day} = {(int)day}");
}

// 获取所有枚举名称
string[] colorNames = Enum.GetNames(typeof(Color));