• 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<T> ,而方法内部使用yield return 该怎么写呢?

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

        internal class AsyncEnumerator : IAsyncEnumerator<string>
        {
            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<bool> 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<string> ReadLineAsync(string path),实作内容如下:

            async static public IAsyncEnumerable<string> 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();
                }
            }
        }
    

      程式码没有错,但编译过不了,观察一下错误讯息:

    错误CS0656:缺少编译器所需成员'System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.GetResult' 
    错误CS0656:缺少编译器所需成员'System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.GetStatus' 
    错误CS0656:缺少编译器所需的成员'系统。 Threading.Tasks.ManualResetValueTaskSourceLogic`1.get_Version' 
    错误CS0656:缺少编译器所需成员'System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.OnCompleted' 
    错误CS0656:缺少编译器所需成员'System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.Reset' 
    错误CS0656:缺少编译器所需的成员'System.Threading.Tasks.ManualResetValueTaskSourceLogic`1.SetException'
    错误CS0656:缺少编译器所需的成员'System.Threading.Tasks.ManualResetValueTaskLogic.cn 
    .SetResult ' 错误CS0656:缺少编译器所需的成员'System.Runtime.CompilerServices.IStrongBox`1.get_Value' 
    错误CS0656:缺少编译器所需的成员'系统。 Runtime.CompilerServices.IStrongBox`1.Value”

    很明显,编译器需要两个型别(1) System.Threading.Tasks.ManualResetValueTaskSourceLogic<T> (2) System.Runtime.CompilerServices.IStrongBox<T>才能完成编译。感谢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<T> and IStrongBox<T>) , while the libraries include the approved API surface area (ManualResetValueTaskSourceCore<T>), and we didn't have time to get the compiler updated.』,简单说就是编译器和框架目前的更新进度不一致,导致少了点什么。既然如此,我们就遵照本草纲目的指示,补上这两个型别,请注意,这两个型别的命名空间必须正确:

    using System;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks.Sources;
    
    
    namespace System.Threading.Tasks{
       
        internal struct ManualResetValueTaskSourceLogic<TResult>
        {
            private ManualResetValueTaskSourceCore<TResult> _core;
            public ManualResetValueTaskSourceLogic(IStrongBox<ManualResetValueTaskSourceLogic<TResult>> 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<object> 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<T> { ref T Value { get; } }
    }
    

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

  • 相关阅读:
    PHP htmlspecialchars和htmlspecialchars_decode(函数)
    使用CURL抓取淘宝页面
    PHP 自定义字符串中的变量名解析
    Notepad++前端开发常用插件介绍
    使用phpExcel实现Excel数据的导入导出(完全步骤)
    moment.js 日期包装类 (说明示例)
    php函数前面加&符号 和 变量前面加&符号的意义
    window 查看端口/杀进程
    eureka 去除注册中心保护机制
    mysql 表关联更新另一张表的数据
  • 原文地址:https://www.cnblogs.com/wwwblender-3dcn/p/10151950.html
Copyright © 2020-2023  润新知