微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

System.InvalidOperationException 使用 GetAwaiter().GetResult() 和 ServiceBusReceiver.PeekMessagesAsync 时 上下文代码示例

如何解决System.InvalidOperationException 使用 GetAwaiter().GetResult() 和 ServiceBusReceiver.PeekMessagesAsync 时 上下文代码示例

上下文

我们使用 GetAwaiter().GetResult() 是因为 PowerShell 的 Cmdlet.ProcessRecord() 不支持 async/await。

代码示例

class Program
{
    static async Task Main(string[] args)
    {
        var topicPath = "some-topic";
        var subscriptionName = "some-subscription";
        var connectionString = "some-connection-string";

        var subscriptionPath = EntityNameHelper.FormatSubscriptionPath(
            topicPath,subscriptionName
        );

        var serviceBusClient = new ServiceBusClient(connectionString);
        var receiver = serviceBusClient.CreateReceiver(queueName: subscriptionPath);

        // This one works. :-) 
        await foreach (var item in GetMessages(receiver,maxMessagesPerFetch: 5))
        {
            Console.WriteLine("async/await: " + item);
        }

        // This one explodes.
        var enumerator = GetMessages(receiver,maxMessagesPerFetch: 5).GetAsyncEnumerator();
        while (enumerator.MoveNextAsync().GetAwaiter().GetResult())
        {
            // Unhandled exception. system.invalidOperationException: Operation is not valid due to the current state of the object.
            //    at NonSync.IAsyncEnumerable.Program.GetMessages(ServiceBusReceiver receiver,Int32 maxMessagesPerFetch)+System.Threading.Tasks.sources.IValueTaskSource<System.Boolean>.GetResult()
            //    at NonSync.IAsyncEnumerable.Program.Main(String[] args) in C:\dev\mediavalet\MediaValet.Learning\entropy\NonSynchronousDotNet\NonSync.IAsyncEnumerable\Program.cs:line 42
            //    at NonSync.IAsyncEnumerable.Program.<Main>(String[] args)
            Console.WriteLine("GetAwaiter().GetResult(): " + enumerator.Current);
        }
    }

    public static async IAsyncEnumerable<string> GetMessages(
        ServiceBusReceiver receiver,int maxMessagesPerFetch
    )
    {
        yield return "Foo";
        var messages = await receiver.PeekMessagesAsync(maxMessagesPerFetch);
        yield return "Bar";
    }
}

问题

这是怎么回事?我们如何在不更改 GetMessages 的情况下修复它?

解决方法

根据 ValueTask<TResult> 结构的文档:

不应在 ValueTask<TResult> 实例上执行以下操作:

• 多次等待实例。
• 多次调用AsTask
• 在操作尚未完成时使用 .Result.GetAwaiter().GetResult(),或多次使用它们。
• 使用一种以上的技术来使用实例。

如果您执行上述任何操作,结果是不确定的。

您可以做的是使用 AsTask 方法将 ValueTask<bool> 转换为 Task<bool>

while (enumerator.MoveNextAsync().AsTask().GetAwaiter().GetResult())
,

此答案通过代码示例补充了 Theodor 的答案。我们的具体问题是我们在 GetResult() 完成之前调用了 ValueTask。文档指定这是不允许的:

ValueTask 实例只能等待一次,并且消费者在实例完成之前不能读取 Result。如果这些限制是不可接受的,请通过调用 AsTask 将 ValueTask 转换为 Task。 (加了重点)。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

var enumerator = GetAsyncEnumerable().GetAsyncEnumerator();

while (true)
{
    var moveNext = enumerator.MoveNextAsync();
    var moveNextAwaiter = moveNext.GetAwaiter();

    Console.WriteLine("ValueTask.IsCompleted: {0}",moveNext.IsCompleted);

    try
    {
        if (moveNextAwaiter.GetResult())
        {
            Console.WriteLine("IAsyncEnumerator.Current: {0}",enumerator.Current);
            continue;
        }

        Console.WriteLine("Done! We passed the end of the collection.");
        break;
    }
    catch (InvalidOperationException)
    {
        Console.WriteLine("Boom! GetResult() before the ValueTask completed.");
        continue;
    }
}

async IAsyncEnumerable<int> GetAsyncEnumerable()
{
    yield return 1;
    await Task.Delay(1000);
    yield return 2; // <---- We never access this,because GetResult() explodes.
    yield return 3;
}

输出:

ValueTask.IsCompleted: True
IAsyncEnumerator.Current: 1

ValueTask.IsCompleted: False
Boom! GetResult() before the ValueTask completed.

ValueTask.IsCompleted: True
IAsyncEnumerator.Current: 3

ValueTask.IsCompleted: True
Done! We passed the end of the collection.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?