我正在尝试将我的foreach函数转换为linq函数
这是我的正常代码[正常工作]
var tList = new List<Func<Task<bool>>> { Method1, Method2 };
tList.Shuffle();
int succeed = 0;
foreach (var task in tList)
{
var result = await task();
if(!result)
break;
succeed += 1;
}
MessageBox.Show(succeed == 1 ? "Loading complete." : "Something went wrong!");
此后转换为Linq [给2编译器错误]
var tList = new List<Func<Task<bool>>> { Method1, Method2 };
tList.Shuffle();
int succeed = tList.Select(async task => await task()).TakeWhile(result => result).Count();
MessageBox.Show(succeed == 1 ? "Loading complete." : "Something went wrong!");
错误
- 无法将lambda表达式转换为委托类型&#39; System.Func,bool&gt;&#39;因为有的 块中的返回类型不能隐式转换为
委托退货类型- 无法隐式转换类型System.Threading.Tasks.Task&#39;到&#39; bool&#39;
我想知道为什么编译器会给出这些消息,所以任何帮助都会受到赞赏。
注意:我还尝试了.TakeWhile(async result => await result)
错误
- 异步方法的返回类型必须为void,Task或Task T
方法1和方法2,如果有人想要他们:
public async Task<bool> Method1()
{
await Task.Delay(1000);
Console.WriteLine("Method1");
return false;
}
public async Task<bool> Method2()
{
await Task.Delay(1000);
Console.WriteLine("Method2");
return true;
}
答案 0 :(得分:1)
使用如下的 TakeWhileAsync 扩展方法:
public static async Task<IEnumerable<T>> TakeWhileAsync<T>(this IEnumerable<Task<T>> tasks, Func<T, bool> predicate)
{
var results = new List<T>();
foreach (var task in tasks)
{
var result = await task;
if (!predicate(result))
break;
results.Add(result);
}
return results;
}
必须有一个更优化的解决方案,但是我认为这很容易理解。您遍历任务,等待每个任务完成,然后执行与常规 TakeWhile 方法相同的逻辑。
首先,您需要实际调用方法:tList.Select(func => func()
,然后在新创建的 IEnumerable tList.Select(func => func()).TakeWhileAsync(result => result)
然后您等待,并计算结果:(await tList.Select(func => func()).TakeWhileAsync(result => result)).Count()
.Select(async task => await task()).TakeWhile(result => result)
请记住,异步函数始终会返回一个任务(或无效)。 select块中的lambda返回 IEnumerable result => result
)也将返回 Task
.TakeWhile(async result => await result)
同一问题,您的lambda返回一个任务(因为它是异步的“方法”),它将永远无法用作LINQ谓词。
.TakeWhile(result => result.Result)
这个(根据Simon的回答)确实可以编译,甚至可以在某些情况下使用。 (其中SynchronizationContext没有绑定到单个线程,但这是另一个漫长的话题。)然而,主要的收获是,阻塞异步代码很危险,并且可能导致死锁 >。这是great detailed article。
答案 1 :(得分:0)
第一个和第二个代码之间存在根本区别(不会做同样的事情)。
在第一个代码上,您将迭代任务列表。在第二个你只是将每个任务转换成另一个任务 - 异步lambda的返回类型将永远是一个任务。
因为您按顺序等待每个任务执行的区域。那是你打算做的吗?
尝试这样的事情(未经测试):
var tList = new List<Func<Task<bool>>> { Method1, Method2 };
tList.Shuffle();
int succeed = Task.WaitAll(tList.ToArray())
.TakeWhile(result => result).Count();
MessageBox.Show(
succeed == 1
? "Loading complete."
: "Something went wrong!");
但这仍然是一段奇怪的代码。
答案 2 :(得分:-1)
这只是因为您无法将Task<bool>
转换为bool
..正如编译器指示的那样。
改变这个:
.TakeWhile(result => result)
..对此:
.TakeWhile(result => result.Result)