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

33qvvth1  于 2023-04-08  发布在  .NET
关注(0)|答案(1)|浏览(111)

我浏览了StackOverflow上的其他问题,但其他问题/答案似乎都不符合我的情况:
我在一个类中编写了一个async方法,我需要从另一个类中的重写方法调用该方法,该方法派生自.NET System.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}");
  }
}

现在,在我的类的Cmdlet基类的ProcessRecord覆盖中,我不能使用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
怎么做才是正确的?

pxy2qtax

pxy2qtax1#

得到InvalidOperationException的原因是ValueTask不能像Task那样被同步等待,所以简单的解决方法是用AsTask()方法把它变成Task
枚举器是一次性的,这意味着你应该在使用后处理它们。而IEnumerator继承了IDisposableIAsyncEnumerator继承了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();
  }
}

相关问题