.net 为什么调用不存在的字典键会挂起我的程序?

fnatzsnv  于 2022-12-14  发布在  .NET
关注(0)|答案(1)|浏览(138)

我有一个字典,它以字符串作为键,以异步函数作为值,其定义如下:

_messageMap = new Dictionary<string, Func<UpgradeTask, Task>>
{
    { "Upgrade1", Upgrade1 }
};

函数如下所示:

private async Task Upgrade1(UpgradeTask upgradePayload)
{
    await _databaseFunctions.DoUpgrade("Upgrade1", upgradePayload.UpgradeId);
}

所有这些都包含在一个类中,该类有一个execute方法,该方法将通过它获得的字符串调用相应的函数。它本质上是一个回调机制,用于将来事件发生时。Execute看起来像这样:

public async Task Execute(FutureEvent futureEvent)
{
    var payLoad = JsonSerializer.Deserialize<UpgradeTask>(futureEvent.Message);
    await _messageMap[payLoad.UpgradeId].Invoke(payLoad);
}


然而,如果有效负载曾经有一个不在字典中的UpgradeId,那么这似乎会无限期地挂起。
我期望发生的是,如果UpgradeId存在于字典中,它将调用那个函数。实际上,在那种情况下,它工作得很好。但是,如果UpgradeId在字典中不存在的有效载荷中,它将无限期地挂起。就像它在等待一些从未发生的事情。我以为它会跳过它,甚至可能出错。但它只是默默地失败,并永远挂起。这是一个问题,因为它实际上并没有崩溃的应用程序的其余部分。其他一切似乎都工作正常,但没有回调得到处理,如果有一个事件不存在于字典。
为什么会这样呢?我知道我可以事先检查一下字典里是否有这个词。但是我仍然很困惑为什么wait会永远挂在那里。我想知道我做错了什么。
编辑:GitHub上的一个例子:https://github.com/Johnhersh/DictionaryTimerExample很不幸,这是我能得到的最小的了。进一步简化它可以让我在访问该键时得到预期的抛出行为。

0wi1tuuw

0wi1tuuw1#

您需要检查字典中是否存在该键。如果不进行检查,KetNotFoundException将被抛出,它将停止执行调用Execute方法的方法。它不会挂起,只是停止。
所以这是唯一的解决办法

public async Task Execute(FutureEvent futureEvent)
{
    var payLoad = JsonSerializer.Deserialize<UpgradeTask>(futureEvent.Message);
    if (_messageMap.ContainsKey(payLoad.UpgradeId) {
        await _messageMap[payLoad.UpgradeId].Invoke(payLoad);
    }
}

或者

public async Task Execute(FutureEvent futureEvent)
{
    var payLoad = JsonSerializer.Deserialize<UpgradeTask>(futureEvent.Message);
    if (_messageMap.TryGetValue(payLoad.UpgradeId, out var func) {
        await func.Invoke(payLoad);
    }
}

我还建议返回ValueTask而不是Task,以避免在字典中找不到键时分配Task内存

相关问题