­

C# 8 – using声明 和 异步流

  • 2019 年 11 月 1 日
  • 筆記

这两个主题没什么关系,但是怕文章太短被移除主页。

using声明

using语句块 

尽管.NET Core运行时有垃圾收集器(GC)来负责内存清理工作,但是我们还是要自己确保当非托管资源不再使用的时候应该被清理掉。以前针对实现了IDisposable接口的对象,我们经常会使用using 语句块来这样做: 

class  O references  static void Mgin(stringC]  gx•gs  using (var  = new DbConnection(  db  Console.WriteLine("Start using db...."  Console.WriteLine("End of the Main method");  I reference  public class DbConnection  O references  public void Dispose()  IDisposable  Console.WriteLine( "Db Connection Disposed");

 

这时候它的输出是这样的: 

Start using db.  Db Connection Disposed  End of the main method

 

这样写还是有一点麻烦的,能简单一些就好了。但是而如果不使用using语句的话,那资源就不会被清理: 

Mgin(stringC]  static void  args  new DbConnection( )  db  var  .WriteLine("Start using db...."  Console  Console.WriteLine("End of the Main method");

 

其输出就没有disposed那段了: 

Start using db.  End of the main method

 

using声明 

但是从C# 8开始,我们可以使用using声明来做这件事了,要比之前的using语句块简单一些,直接看例子: 

static v  Elgin(stringC]  gx•gs  = new DbConnection()  db  using var  Console.WriteLine("Start using db...."  Console.WriteLine("End of the Main method");

就是在定义变量前面的地方使用using声明。 

 

这样做的话,在Main方法走完的时候,db这个资源是可以被清理掉的: 

Start using db.  End of the main method  b Connection Disposed

可以看到db被Disposed了,但是您肯定也发现了不同之处:最后两行输出的顺序发生了变化。 

 

在使用using语句块的时候,清理动作发生在using块结束的时候: 

using (var  = new DbConnection(  db  Console.WriteLine("Start using db...."

 

而使用using声明以后,清理动作会发生超出db作用范围的时候,也就是离开Main方法的时候: 

static void Elgin(stringC]  gx•gs  new DbConnection()  db  using var  Console.WriteLine("Start using db...."  Console.WriteLine("End of the Main method");

 

用法

using语句块和using声明还是要结合具体情况来使用。。。 

更详细内容请点击:官方教程

 

异步流 Asynchronous Streams

例子 

private static int Threadld  Thread . CurrentThread . ManagedThreadId ;  O references  static void Elgin(stringC]  gx•gs  new NumberFactory();  var factory =  Console. WriteLine($"  {Threadld}-  Enumerating numbers ");  foreach (var number in factory.GenerateNumbers( count: 5))  Console.WriteLine($"  --{ThreadId}  Console.WriteLine($"  {Threadld}-  {number}."),  Received number:  numbers received." ,

这是一个很简单的控制台程序。它有一个NumberFactory,它可以根据传递的参数来产生一串数字(IEnumerable<int>)。然后在这个程序中把每个数字都打印出来,同时在前边显示出当前的线程ID。 

 

这里面的NumberFactory也是非常的简单: 

public class NumberFactory  I reference  public IEnumerable<int> GenerateNumbers(int count)  for (int i =  0; i < count;  Task. Delay(1ØØØ) .Wait();  yield return i + 1;

这里我做了延迟,模拟读取外部资源的效果。 

 

运行程序(文章考不到挨个输出的停顿效果): 

Enumerating numbers.. .  Received number: 1.

 

Enumerating numbers.. .  Received number:  Received number:  Received number:  Received number:  Received number:  4.  All numbers received .

可以看到所在线程的ID都是1。因为其工作原理就是这样的,程序会阻塞线程以便让NumberFactory来做它的工作。所以说这样不是很理想,最理想的办法是使用C#的异步编程模型,但是在C# 8之前,这是做不到的。但是从C# 8开始,我们就可以这样做了。 

 

Asynchronous Stream异步流 

首先修改NumberFactory,在Task.Delay(1000)前边加上await关键字来代替.Wait()方法,然后再修改返回类型为IAsyncEnumberable<int>,并在前面添加async关键字: 

public async IAsyncEnumerable<int> GenerateNumbers(int count)  for (int i =  0; i < count;  await Task.Delay(1ØØØ);  yield return i + 1;

 

回到Main方法,需要做出两个修改: 

static async Task Mgin(stringC]  gx•gs  new NumberFactory();  var factory =  Console.WriteLine($"  - {Threadld}-  Enumerating numbers ");  await foreach (var number in factory .GenerateNumbers( count:  5))  Console . WriteLine($"  -{ThreadId}  Console.WriteLine($"  - {Threadld}-  Received number:  numbers received.  {number}."),

首先,就是在foreach循环前面加上await关键字,这看起来比较奇怪,但这就是我们遍历异步流的方式。注意是在foreach前边加await,而不是在factory.GenerateNumbers(5)前边加await。 

然后,还需要改变Main方法的返回类型为Task,并加上async关键字。 

 

最后运行程序,看看效果: 

可以看到,线程的ID有时候会发生变化,这就是我们想要的效果。在这里流是异步的,当它await任务的时候,该线程是可以去做其它工作的。而当程序继续执行的时候,它确实可能结束于其它的线程。 

更详细内容请点击:官方教程