gpt4 book ai didi

c# - 为什么我不允许在返回 IAsyncEnumerable 的方法中返回 IAsyncEnumerable

转载 作者:行者123 更新时间:2023-12-04 04:30:23 28 4
gpt4 key购买 nike

我有以下界面:

public interface IValidationSystem<T>
{
IAsyncEnumerable<ValidationResult> ValidateAsync(T obj);
}
我正在尝试以这种方式实现它:
public class Foo
{ }

public class Bar
{ }

public class BarValidationSystem : IValidationSystem<T>
{
public async IAsyncEnumerable<ValidationResult> ValidateAsync(Bar bar)
{
var foo = await GetRequiredThingAsync();

return GetErrors(bar, foo).Select(e => new ValidationResult(e)).ToAsyncEnumerable();
}

private static IEnumerable<string> GetErrors(Bar bar, Foo foo)
{
yield return "Something is wrong";
yield return "Oops something else is wrong";
yield return "And eventually, this thing is wrong too";
}

private Task<Foo> GetRequiredThingAsync()
{
return Task.FromResult(new Foo());
}
}
但这不能编译:

CS1622 Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration.


我知道我可以通过迭代可枚举来修复:
foreach (var error in GetErrors(bar, foo))
{
yield return new ValidationResult(error);
}
或者通过返回 Task<IEnumerable<ValidationResult>> :
public async Task<IEnumerable<ValidationResult>> ValidateAsync(Bar bar)
{
var foo = await GetRequiredThingAsync;

return GetErrors(bar, foo).Select(e => new ValidationResult(e));
}
但我想明白为什么我不能返回 IAsyncEnumerable就我而言。写“经典”时 IEnumerable方法,您可以返回 IEnumerable或 yield 返回几个值。为什么我不能对 IAsyncEnumerable 做同样的事情?

最佳答案

This looks like a bug or at least an unintentional limitation, when reading the spec proposal.


规范指出 yield 的存在导致迭代器方法;以及两者的存在 asyncyield导致异步迭代器方法。

But I would like to understand why I cannot return an IAsyncEnumerable in my case.

async关键字使其成为异步迭代器方法。由于您需要 asyncawait ,那么你需要使用 yield以及。

When writing "classic" IEnumerable methods, you can either return an IEnumerable or yield return several values. Why am I not allowed to do the same with IAsyncEnumerable?


与两者 IEnumerable<T>IAsyncEnumerable<T> ,您可以在直接返回可枚举之前执行同步工作。在这种情况下,该方法并不特殊;它只是做了一些工作,然后将一个值返回给它的调用者。
但是您不能在返回异步枚举器之前进行异步工作。在这种情况下,您需要 async关键词。添加 async关键字强制方法是异步方法或异步迭代器方法。
换句话说,在 C# 中,所有方法都可以分为以下不同类型:
  • 常规方法。否 asyncyield展示。
  • 迭代器方法。一个 yield体内无async .必回IEnumerable<T> (或 IEnumerator<T>)。
  • 异步方法。安 async不存在 yield .必须返回一个 tasklike。
  • 异步迭代器方法。两者 asyncyield存在。必回IAsyncEnumerable<T> (或 IAsyncEnumerator<T>)。

  • 再换一个角度,考虑实现这种方法必须使用的状态机,尤其是当 await GetRequiredThingAsync()代码运行。
    在没有 yield的同步世界, GetRequiredThing()将在返回可枚举之前运行。在同步世界与 yield , GetRequiredThing()将在请求可枚举的第一项时运行。
    在没有 yield 的异步世界中, await GetRequiredThingAsync()将在返回异步枚举之前运行(在这种情况下,返回类型将为 Task<IAsyncEnumerable<T>> ,因为您必须执行异步工作才能获得异步枚举)。在异步世界中与 yield , await GetRequiredThingAsync()将在请求可枚举的第一项时运行。
    一般来说,在返回可枚举之前要进行工作的唯一情况是进行前提条件检查(本质上是同步的)。进行 API/DB 调用是不正常的;大多数情况下,预期的语义是任何 API/DB 调用都将作为枚举的一部分完成。换句话说,即使是同步代码也应该使用 foreachyield ,就像异步代码被迫做的那样。
    附带说明一下,在这些场景中使用 yield* 会很好。对于同步和异步迭代器,但 C# 不支持。

    关于c# - 为什么我不允许在返回 IAsyncEnumerable 的方法中返回 IAsyncEnumerable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65917317/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com