如何在非异步(同步)覆盖中使用异步方法?



我浏览了StackOverflow上的其他问题,但其他问题/答案似乎都不符合我的情况:

我已经在一个类中编写了一个async方法,我需要从派生自。netSystem.Management.Automation.Cmdlet类的另一个类中的重写方法中调用。

我通常会这样调用我的方法:
public async Task TestReadingFile()
{
using MyReader reader = new MyReader(SetupMyStream("Contoso.txt"));
await foreach (MyDataObject obj in reader.GetFrames())
{
Debug.Print($"{reader.Progress}: {obj.GetType().Name} - {obj}");
}
}

现在,在我的类的ProcessRecord覆盖Cmdlet基类我不能使用async。但是,当然,我想等待结果。

我该怎么做?


我的期望是使用这样的东西:

protected override void ProcessRecord()
{
using MyReader reader = new MyReader(MyFilePath);
IAsyncEnumerator<MyDataObject> enumerator = reader.GetFrames().GetAsyncEnumerator();
while (enumerator.MoveNextAsync().GetAwaiter().GetResult())
{
MyDataObject obj = enumerator.Current;
Debug.Print($"{reader.Progress}: {obj.GetType().Name} - {obj}");
}
}

但是这种方法会抛出一个InvalidOperationException

这是怎么做的正确的方式?


得到InvalidOperationException的原因是ValueTask不能像Task那样同步等待。所以简单的解决办法就是用AsTask()方法把它变成Task

枚举数是一次性的,这意味着您应该在使用后将其丢弃。IEnumerator继承IDisposable,IAsyncEnumerator继承IAsyncDisposable。在正常情况下,你应该使用await using,但由于方法是同步的,我们必须自己降低这个东西。首先,将其转换为try-finally结构,然后同步等待返回的任务。

protected override void ProcessRecord()
{
using MyReader reader = new MyReader(MyFilePath);
IAsyncEnumerator<MyDataObject> enumerator = reader.GetFrames().GetAsyncEnumerator();
try
{
while (enumerator.MoveNextAsync().AsTask().GetAwaiter().GetResult())
{
MyDataObject obj = enumerator.Current;
Debug.Print($"{reader.Progress}: {obj.GetType().Name} - {obj}");
}
}
finally
{
enumerator?.DisposeAsync().AsTask().GetAwaiter().GetResult();
}
}