C#核心知识

委托

如何声明一个委托:通过 【delegate 返回值类型 委托名称】 的格式来定义

如何使用一个委托:使用new关键字,并传入和声明委托的构造相同的方法名,比如:new 委托名称(与委托的参数和返回值相同的一个方法名)

如何调用一个委托:将new关键字返回的实例调用Invoke方法,或者像调用一个方法一样调用它,就像方法一个调用都可以

什么是多播委托:顾名思义,多播委托可以注册多个实现了委托的方法。

如何使用多播委托:通过+=,-=注册,取消注册委托

预定义委托:通过Action,Func来实现,他们的区别在于Action没有返回值,Func有返回值,返回值在最后一个泛型里。

匿名函数经常和委托一起使用,语法:()=>{}

事件

事件是在委托的基础上做的一个安全的处理,避免直接调用委托,而是通过+=,-=这种方式去注册,取消注册委托。并且在内部实现了线程安全的操作。

如果要研究源码可以在SharpLab中看到用原始方法是如何实现了高级语法的。

多线程

什么是线程?

一个进程有多个线程,线程是操作系统中独立运行的最小单位。

为什么要用多线程?

希望能同时运行多个任务,提高效率。

什么是线程池?

是一组预先创建的线程,可以被重复利用来执行任务。

什么是线程安全?

多个线程同时访问共享资源时,对它的访问不会产生数据不一致的后果。

同步机制:用于协调多个线程访问的执行顺序去访问共享资源,避免数据不一致的问题。通过lock(obj){}的方式实现同步。

lock语法糖实际是对Monitor的一个封装。

原子操作:在执行任务时要么全部执行,要么全部不执行,确保了数据的一致性。 通过Interlocked类实现原子操作

并行操作:使用并行操作(PLinq)可以大幅提高效率,使用AsParallel方法可以确保并行操作的执行。

如果前台线程消亡,后台线程也要跟着消亡,Main函数就是一个前台线程。

如何创建一个线程?

new Thread(方法名称).Start(方法的参数)

{

IsBackground = ,

....... // 配置

}

Join方法可以让当前线程先执行完毕,确保后面的线程不会在它之前执行。

Interrupt可以中断线程的执行

信号量(Semaphore):可以理解为高速公路的闸口和车道数,第一个参数控制开启的闸口数,第二个参数控制车道数。

异步编程

异步不意味着多线程,单线程也可以是异步的。异步默认是使用线程池的,可以从线程ID中观察的到,每次的ID都不一样。

多线程适合CPU密集型的操作,适合长期运行的任务

异步适合IO密集型的操作,适合短暂的小任务,例如:服务器的后端接口;异步可以查看到线程执行的状态。

异步任务的创建:

1、Task.Run()

2、Task.Factory.StartNew()

3、new Task().Start();

特性:

1、将方法标记为async后,方可在方法中使用await,还有一种同步的写法但不推荐:InvokeTask().GetAwaiter().GetResult();

2、async+await会将方法包装为状态机

3、异步编程具有传染性

async void这种写法几乎只用于对事件的注册。

常见的阻塞情形:

1、Task.Wait() Task.Result如果任务没有完成,则会阻塞当前线程,容易造成死锁。

2、InvokeTask().GetAwaiter().GetResult(); 依旧是个阻塞写法

3、Thread.Sleep(),使用异步时应该为Task.Delay(),这种写法会立即释放当前线程

4、IO耗时的操作

如何开启多个异步任务?

Task.WhenAll(task),Task.WhenAny(task),不要在for循环中await。

如何取消异步任务?

使用CancellationToken实例的Cancel方法,同时配合IsCancellationRequested属性可以在任务中精确控制是否继续执行任务。

任务超时如何实现?

在创建CancellationTokenSource时传入超时时间,比如:new CancellationTokenSource(2000);

注意事项

需要注意的是每次需要手动释放CancellationTokenSource

??运算符,当左边的参数不为空则返回它,如果为空则返回右边的参数

有哪些同步机制?

SemaphoreSlim 推荐,用法简单

Channel

第三方库 - AsyncLock,比较复杂适用于大型项目

如何在在同步方法中调用异步?

1、应避免使用xxx.Wait(),xxx.Result,有可能导致死锁,且无法捕获异常。

2、应避免使用async void,无法捕获到内部异常,内部不加异常捕获会导致程序挂掉

3、InvokeTask().GetAwaiter().GetResult(); 可以捕获到内部异常。

4、SafeFireForget:async void SafeFireForget(Task task, Action? completed, Action<Exception> expection),第一个参数是异步执行的业务方法,第二个参数是异步任务完成后的回调委托,第三个参数是异步任务出现异常的回调委托

5、ContinueWith:Job().ContinueWith(xxxTask),在异步任务完成后调用它的ContinueWith方法,参数是对任务完成与否的处理方法。

GC

.NET中将引用对象分为三类,第0代,第1代,第2代对象,一般会优先进行第0代回收, 然后将未成功回收的放到第1代中,如果第1代对象再次未回收成功会放到第2代中,这样做可以减少回收的成本,提高效率。

在C#中,析构函数(也称为终结器)主要用于释放非托管资源(如文件句柄、数据库连接、操作系统句柄等)。

复制代码
class ResourceWrapper
{
    ~ResourceWrapper() // 析构函数
    {
        // 释放非托管资源
        CloseHandle(fileHandle);
    }
}

重要配置

在项目文件xxx.csproj中修改以下配置

工作站与服务器模式

工作站模式:适合内存占用小的程序和桌面应用,回收频率高,是单线程的。

服务器模式:适合内存占用大的程序,回收频率低,吞吐量高,是多线程的。

1、true - 服务器模式,false - 工作站模式

<ServerGarbageCollection>true</ServerGarbageCollection>

普通GC与后台GC

普通GC:会导致单次停顿时间变长(例如UI线程的卡死),但消耗的资源少,支持压缩处理。

后台GC:单次停顿时间短,但停顿的频率多,消耗的资源多,不支持压缩处理。

2、true - 启动后台GC,false - 普通GC

<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>

相关推荐
csdn_aspnet24 分钟前
C# 如何验证磁盘路径,如:D:\\m\aa.txt
c#
电商api接口开发2 小时前
ASP.NET MVC 入门指南四
c#·asp.net·mvc
CHQIUU2 小时前
跨语言哈希一致性:C# 与 Java 的 MD5 之战?
java·c#·哈希算法
技术拾荒者3 小时前
c#加密证件号的中间部分,改为*号
c#
weixin_423995004 小时前
unity 读取csv
unity·c#
wkj0015 小时前
java 和 C#操作数据库对比
java·数据库·c#
码观天工8 小时前
.NET AI Preview 2 发布:从 .NET Aspire 支持到 Qdrant 向量数据库集成,助你快速构建云原生 AI 应用
ai·c#·.net·向量数据库·aspire·qdrant
时光追逐者8 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 36 期(2025年4.21-4.27)
c#·.net·.netcore