我们一样就拿ReadLineAsync 来示范,首先建立一个类别实作IAsyncEnumerator ,当然这也包含了实作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 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:缺少编译器所需的成员
很明显,编译器需要两个型别(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.』,简单说就是编译器和框架目前的更新进度不一致,导致少了点什么。既然如此,我们就遵照本草纲目的指示,补上这两个型别,请注意,这两个型别的命名空间必须正确:
点击(此处)折叠或打开
- 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。