.NET 5+ 已过时的功能

数组淘汰

.NET Framework 2以上的版本中,ArrayList可以说已经被淘汰了,应该用泛型类中的List

https://www.cnblogs.com/cdaniu/p/15936840.html

Thread类淘汰的方法

Abort() .net5.0 开始过时, 被废弃的主要原因是 不能及时停止线程。方法仅通知线程“嘿,您可以立即停止”,但不会终止该线程。因此,该线程可以在Abort之后保持 Activity 一会儿。

Thread.Abort在.NET Core 中从未实现过。CancellationToken已成为一个安全且被广泛接受的Thread.Abort替代者

Suspend() .net5.0开始过时 被废弃的主要原因是因为其使用很容易造成线程死锁(Deadlock)。

Resume() .net5.0开始过时 被废弃的主要原因是因为其使用很容易造成线程死锁(Deadlock)。

全局程序集缓存

到.NET 4.5 发布时,几乎没有应用程序将 GAC 用于非微软库。主要的例外是商业库,但即使是这些库也已经转向了对 NuGet 更友好的交付模型。

Remoting

.NET Remoting是受DCOMJava Remoting(Java RMI)的启发。这三种方法的基本思想都是一个应用程序可以使用代理对象来操作在另一个应用程序中运行的真实对象。虽然它在技术上可以工作,但.NET Remoting 从来就没有流行过,因为要正确地使用它很难,而且人们一般认为它很脆弱。

考虑到这一点,.NET Core 从未实现过.NET Remoting API。就像 GAC API 一样,它只有不可操作的占位符。因此,它们也被标记为已过时,而最终目的是将其删除。

System.Collections

(淘汰)DictionaryEntry=(新)KeyValuePair

(淘汰)约束执行区域CER

GC.sever(淘汰)

编程是个人爱好

CancellationToken的使用

使用场景

在.net core随处可见的async await的异步使用,这就可以用到CancellationToken来取消任务。

场景一:如在web应用中,用户点击了下载文件(耗时操作),当用户不想下载了,直接点取消,但是我们异步代码中没响应取消的话,还是会执行下去这个耗时操作的,这就耗费了不必要的服务器资源。

一、开始使用

CancellationTokenSource:用于控制和生成CancellationToken

CancellationToken:取消令牌,可以注册取消回调等操作

1、先实例化CancellationTokenSource

2、注册取消回调

3、启动一个Task,模拟耗时操作

4.调用CancellationTokenSource的CancelAfter方法,表示多少毫秒后取消,也可使用Cancel方法立即取消

5、IsCancellationRequested属性判断任务是否取消,没取消则一直输出i

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CancellationTokenSource cts=new CancellationTokenSource();
cts.Token.Register(() => { Console.WriteLine("任务已停止"); });

Task.Run(() =>
{
int i = 1;
while (!cts.IsCancellationRequested)
{
i++;
Console.WriteLine(i);
Task.Delay(500).Wait();
}

});
cts.CancelAfter(2000);
Console.ReadLine();

二、上面介绍完基本使用,下面使用下具体场景

2.1 如桌面应用,当用户按下某个键的时候取消我当前的任务

简单改造下上面的代码就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CancellationTokenSource cts=new CancellationTokenSource();
cts.Token.Register(() => { Console.WriteLine("任务已停止"); });

Task.Run(() =>
{
int i = 1;
while (!cts.IsCancellationRequested)
{
i++;
Console.WriteLine(i);
Task.Delay(500).Wait();
}

});

var key=Console.ReadKey();
if(key.Key==ConsoleKey.A)
{
cts.Cancel();
}
Console.ReadLine();

当我们按下a键时就可以取消任务了。

img

2.2 web api程序中取消操作只需要在接口参数加上CancellationToken就可以了,当我们取消请求的时候,会自动将CancellationToken传进来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[HttpGet]
public async Task<IActionResult> CancelDownLoad(CancellationToken cancellationToken)
{
try
{
var _client = _httpClient.CreateClient("bigDownLoad");
_client.DefaultRequestHeaders.Range = new RangeHeaderValue(0, 1024 * 1024 * 50);
await Task.Delay(1000);
if (!cancellationToken.IsCancellationRequested)
{
var resp = await _client.GetAsync("http://du.cainiaoxt.cn/dd.php/windows_7_ultimate_x64_2023.iso",cancellationToken);
if (resp.StatusCode != System.Net.HttpStatusCode.OK)
{
string chunkFileFolder = @"D:\";
string bigFileName = chunkFileFolder + @"\bigFile" + new Random().Next(0, 10);
using (FileStream fs = new FileStream(bigFileName, FileMode.Create))
{
var respStream = await resp.Content.ReadAsStreamAsync();
await respStream.CopyToAsync(fs);
await respStream.FlushAsync();
}
}
return Ok();
}
else
{
cancellationToken.ThrowIfCancellationRequested();
return BadRequest("下载任务取消!");
}
}
catch (OperationCanceledException ex)
{
Console.WriteLine("下载任务取消!"+ex.Message);
return BadRequest("下载任务取消!");
}
}

方便演示,直接用浏览器访问接口,然后马上取消

img

img

此CancellationToken参数也可以传递给其他异步方法,IsCancellationRequested属性就是判断任务是否取消,如果取消我们可以调用ThrowIfCancellationRequested方法来抛出OperationCanceledException异常,进行其他操作。

三、关联取消

关联取消就是将多个CancellationToken关联起来生成一个新的CancellationTokenSource,当关联的CancellationTokenSource有一个取消时,这个新的CancellationTokenSource也会被取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// See https://aka.ms/new-console-template for more information
CancellationTokenSource cts=new CancellationTokenSource();
cts.Token.Register(() => { Console.WriteLine("任务1已停止"); });

CancellationTokenSource cts2 = new CancellationTokenSource();
cts2.Token.Register(() => { Console.WriteLine("任务2已停止"); });

CancellationTokenSource cts3 = new CancellationTokenSource();
cts3.Token.Register(() => { Console.WriteLine("任务3已停止"); });
var linkTokenSource=CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cts2.Token, cts3.Token);

linkTokenSource.Token.Register(() => { Console.WriteLine("关联token取消"); });
Task.Run(() =>
{
int i = 1;
while (!cts.IsCancellationRequested)
{
i++;
Console.WriteLine("任务1:"+i);
Task.Delay(500).Wait();
}

});

Task.Run(() =>
{
int i = 1;
while (!cts2.IsCancellationRequested)
{
i++;
Console.WriteLine("任务2:"+i);
Task.Delay(500).Wait();
}

});

Task.Run(() =>
{
int i = 1;
while (!cts3.IsCancellationRequested)
{
i++;
Console.WriteLine("任务3:"+i);
Task.Delay(500).Wait();
}

});

Task.Run(() =>
{
int i = 1;
while (!linkTokenSource.IsCancellationRequested)
{
i++;
Console.WriteLine("关联token任务:" + i);
Task.Delay(500).Wait();
}

});

var key=Console.ReadKey();
if(key.Key==ConsoleKey.A)
{
cts.Cancel();
}
Console.ReadLine();

改造一下上面的代码,使用CancellationTokenSource的静态方法CreateLinkedTokenSource将多个CancellationTokenSource关联起来,当我们输入a时,取消任务1,此时也会同时取消新的关联任务

img

Thread.Abort()旧方法

线程调用Thread.Abort()方法后,这会给线程注入ThreadAbortException异常,导致线程被终结。该异常可在任何时刻发生并可能彻底摧毁应用程序。另外,使用该技术也不一定总能终止线程,可以通过处理该异常并调用Thread.ResetAbort方法来拒绝被终止。因此并不推荐使用Abort方法来关闭线程。可优先使用一些其他方法,比如提供一个CancellationToken方法来取消线程的执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace AbortAndResetDemo
{
class Program
{
static void PrintNumbersWithDelay()
{
WriteLine("Starting...");
int i = 1;
Cycle_Print:
try
{
for (; i < 10; i++)
{
Sleep(TimeSpan.FromSeconds(2));
WriteLine(i);
}
}
catch (ThreadAbortException ex)
{
WriteLine($"After Abort, {CurrentThread.Name} state: {CurrentThread.ThreadState}");
Thread.ResetAbort();
WriteLine($"After ResetAbort, {CurrentThread.Name} state: {CurrentThread.ThreadState}");
goto Cycle_Print;
}
}

static void Main(string[] args)
{
WriteLine("Starting program...");
Thread t = new Thread(PrintNumbersWithDelay);
t.Name = "PrintThread";
t.Start();
Sleep(TimeSpan.FromSeconds(6));
t.Abort();
}
}
}

可使用Ctrl+F5直接运行程序,从而避免自动退出程序,看不到程序结果的问题。


相关链接(侵删)

  1. .NET 5+ 中已过时的功能
  2. c#之CancellationToken的使用
  3. Thread.Abort 已过时
  4. 多线程编程实战:Abort()与ResetAbort()

=================我是分割线=================

欢迎到公众号来唠嗑: