如何不创建委托且匿名调用Lambda?解决CS0149编译错误
首先明确说:在当前的C#版本中,没办法完全绕开委托转换或者命名,直接创建并立即调用Lambda表达式——不管是同步还是异步的情况,原因都和C#的类型系统有关:Lambda表达式本身是「无类型的」,编译器必须知道它要转换成哪个具体的委托类型(比如Func<int>、Func<Task<int>>)才能正确编译,而立即调用的场景里没有足够的上下文让编译器自动推断这个类型。
先看同步场景的问题
你尝试的int i = (() => 42)();编译报错CS0149 方法名称缺失,本质就是编译器不知道这个Lambda对应的委托类型是什么。目前确实只有两种解决方式:
- 用命名的本地方法:
int Return42() => 42; int i = Return42(); - 显式转换为对应的委托类型:
int i = ((Func<int>)(() => 42))();
没有第三种「既不命名也不转委托」的方式,因为编译器必须明确Lambda的类型才能生成可执行代码。
再看你的异步场景需求
你想用异步Lambda替代Task.ContinueWith,尝试的Task<int> future = (async () => (await RetrieveLookupFromFarAway())["42"].First())();同样会因为类型推断失败报错,解决方式和同步场景类似:
要么显式转换为Func<Task<int>>:
Task<int> future = ((Func<Task<int>>)(async () => (await RetrieveLookupFromFarAway())["42"].First()))();
要么用命名的异步本地方法:
async Task<int> GetTargetValueAsync() { var lookup = await RetrieveLookupFromFarAway(); return lookup["42"].First(); } Task<int> future = GetTargetValueAsync();
额外的异步最佳实践建议
其实按照Stephen Cleary的建议用await替代ContinueWith,更自然的写法是直接把这段逻辑封装成一个异步方法(就像上面的本地方法那样),而不是强行写立即调用的异步Lambda——这样代码可读性更高,也更容易维护,还能避免Lambda类型转换的麻烦。比如在一个异步方法里直接写:
async Task<int> ProcessLookupAsync() { var remoteLookup = await RetrieveLookupFromFarAway(); return remoteLookup["42"].FirstOrDefault(); // 建议加FirstOrDefault避免空键异常 }
然后调用var resultTask = ProcessLookupAsync();就可以了,完全符合异步编程的最佳实践。
内容的提问来源于stack exchange,提问作者Kasper van den Berg

