如何在不添加无法访问的代码的情况下编译此异步 lambda?

How do I get this async lambda to compile without adding unreachable code?

我有一个方法:

void MyMethod<T>(params Func<T>[] funcs) { }

我想用异步 lambda 调用它:

MyMethod(async () => 1, async () => 2, async () => 3);

有效!但是如果我想让第三个 lambda 抛出异常呢?

MyMethod(async () => 1, async () => 2, async () => { throw new Exception(); });

上面没有编译,它给出了两个相同的错误:

CS0201 Only assignment, call, increment, decrement, and new object expressions can be used as statements

我不确定为什么会出现此错误,但我明白为什么它无法编译 - 前两个 lambda 是 Func<Task<int>> 而最后一个是 Func<Task>。我希望它能给我一个更好的编译错误,但让我们把这个问题放在一边。

如何获取要编译的代码?我可能必须告诉编译器我想为第三个异步 lambda 生成什么类型​​的任务。我发现的一种方法是在 throw 语句之后指定一个 return 语句:

MyMethod(async () => 1, async () => 2, async () => { throw new Exception(); return 3; });

除了丑陋和令人困惑之外,它还会生成编译器警告:

CS0162 Unreachable code detected

如何让编译器满意?如何避免无法访问的代码只是为了编译?还有另一种方法可以指定异步 lambda 返回的任务类型吗?

还有,为什么我在上面的例子中会出现CS0201错误?

问题是编译器将您的 T 推断为 Task,因为最后一个 lambda 没有 return 类型。

因此,它会尝试将第一个 lambda 解析为没有 return 值,这意味着它们必须作为语句有效,而不是表达式。由于 1 作为语句无效,所以你这个听起来很奇怪的错误。

要使您的代码可以编译,请显式传递泛型类型参数:

MyMethod<Task<int>>(async () => 1, async () => 2, async () => { throw new Exception(); });

example

第一个示例中的 lambda 不会是 Func<Task<int>>(没有上下文,它将是 Action),但它是该委托的有效 lambda。由于它对您想要的委托有效,只需将其转换为:

MyMethod(async () => 1, 
    async () => 2, 
    (Func<Task<int>>)(async () => { throw new Exception(); }));