C# 8.0 抢先看 -- Async Stream

Posted petewell

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 8.0 抢先看 -- Async Stream相关的知识,希望对你有一定的参考价值。

在目前版本中异步迭代使用 yield return 的暂时解决方案说明。


本篇文章使用环境
开发环境 Visual Studio 2019 Preview 1 (16.0.0 Preview 1)
框架?????? .NET Core 3.0.0-preview-27122-01
编译器??? C# 8.0 beta

上一篇简单示范了在类中实践 Async Stream 的方式, 如果今天是一个方法要回传 IAsyncEnumerable ,而方法内部使用 yield return 该怎么写呢?

我们一样就拿 ReadLineAsync 来示范,首先建立一个类实践 IAsyncEnumerator ,当然这也包含了实践 IAsyncDisposable:

    internal class AsyncEnumerator : IAsyncEnumerator
    
        private readonly StreamReader _reader;

        private bool _disposed;

        public string Current  get; private set; 

        public AsyncEnumerator(string path)
        
            _reader = File.OpenText(path);
            _disposed = false;
        
        async public ValueTask MoveNextAsync()
        
            var result = await _reader.ReadLineAsync();
            Current = result;
            return result != null;
        
        async public ValueTask DisposeAsync()
        
            await Task.Run(() => Dispose());
        

        private void Dispose()
        
            Dispose(true);
            GC.SuppressFinalize(this);
        

        private void Dispose(bool disposing)
        
            if (!this._disposed)
            
                if (_reader != null)
                
                    _reader.Dispose();
                
                _disposed = true;
            
        
    

接着建立另外一个类, 这个类很简单,只包含一个静态的方法 async static public IAsyncEnumerable ReadLineAsync(string path),实践内容如下:

        async static public IAsyncEnumerable ReadLineAsync(string path)
        

            var enumerator = new AsyncEnumerator(path);
            try
            
                while (await enumerator.MoveNextAsync())
                
                    await Task.Delay(100);
                    yield return enumerator.Current;
                
            
            finally
            
                await enumerator.DisposeAsync();
            
        
    

程序没有错,但编译过不了,观察一下错误消息:

error CS0656: Missing compiler required member ‘System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.GetResult‘
error CS0656: Missing compiler required member ‘System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.GetStatus‘
error CS0656: Missing compiler required member ‘System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.get_Version‘
error CS0656: Missing compiler required member ‘System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.OnCompleted‘
error CS0656: Missing compiler required member ‘System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.Reset‘
error CS0656: Missing compiler required member ‘System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.SetException‘
error CS0656: Missing compiler required member ‘System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.SetResult‘
error CS0656: Missing compiler required member ‘System.Runtime.CompilerServices.IStrongBox`1.get_Value‘
error CS0656: Missing compiler required member ‘System.Runtime.CompilerServices.IStrongBox`1.Value‘

很明显,编译器需要两个类型 (1)? System.Threading.Tasks.ManualResetValueTaskSourceLogic (2) System.Runtime.CompilerServices.IStrongBox 才能完成编译。感谢 open source 与 git hub,在微软的 dotnet/corclr 的项目中找到了这么一段讨论 ~~ ManualResetValueTaskSourceLogic`1 missing in System.Private.CoreLib #21379 ,有位 stephentoub (应该是微软员工而且是这个项目的成员) 提到‘It‘s not missing exactly, but like @benaadams said things are just out-of-sync between the compiler and library in Preview 1. The compiler is looking for the old design (ManualResetValueTaskSourceLogic and IStrongBox), while the libraries include the approved API surface area (ManualResetValueTaskSourceCore), and we didn‘t have time to get the compiler updated. You just need to include a bit of boilerplate in your app’,简单说就是编译器和框架目前的更新进度不一致,导致少了点什么。既然如此,我们就遵照本草纲目的指示,补上这两个类型,请注意,这两个类型的命名空间必须正确:

using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks.Sources;


namespace System.Threading.Tasks
   
    internal struct ManualResetValueTaskSourceLogic
    
        private ManualResetValueTaskSourceCore _core;
        public ManualResetValueTaskSourceLogic(IStrongBox> parent) : this()  
        public short Version => _core.Version;
        public TResult GetResult(short token) => _core.GetResult(token);
        public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token);
        public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags);
        public void Reset() => _core.Reset();
        public void SetResult(TResult result) => _core.SetResult(result);
        public void SetException(Exception error) => _core.SetException(error);
    


namespace System.Runtime.CompilerServices

    internal interface IStrongBox  ref T Value  get;  



补上去后就大功告成,可以快乐地异步 yielld return。故事还没完,待续........


原文:大专栏  C# 8.0 抢先看 -- Async Stream (2)


以上是关于C# 8.0 抢先看 -- Async Stream的主要内容,如果未能解决你的问题,请参考以下文章

C# 9.0 新功能抢先看!

C# Async与Await的使用

[译] C# 5.0 中的 Async 和 Await (整理中...)

C#异步编程看这篇就够了

async-await 线程分析

我也来说说C#中的异步:async/await

(c)2006-2024 SYSTEM All Rights Reserved IT常识