【发布时间】:2013-10-11 22:15:10
【问题描述】:
编辑
我已经更改了问题的标题,以反映我遇到的问题,以及如何轻松实现这一目标的答案。
我正在尝试使第二种方法返回Task<TResult> 而不是第一种方法中的Task,但是由于尝试修复它,我遇到了一系列错误。
- 我在
await body(partition.Current);之前添加了return - 反过来,它要求我在下面添加一个退货声明,所以我在下面添加了
return null - 但现在 select 语句抱怨它无法从查询中推断类型参数
- 我将
Task.Run更改为Task.Run<TResult>,但没有成功。
我该如何解决?
第一种方法来自http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx,第二种方法是我正在尝试创建的重载。
public static class Extensions
{
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate
{
using (partition)
while (partition.MoveNext())
await body(partition.Current);
}));
}
public static Task ForEachAsync<T, TResult>(this IEnumerable<T> source, int dop, Func<T, Task<TResult>> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate
{
using (partition)
while (partition.MoveNext())
await body(partition.Current);
}));
}
}
使用示例:
通过这种方法,我想并行和异步下载多个文件:
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Artist artist = await GetArtist();
IEnumerable<string> enumerable = artist.Reviews.Select(s => s.ImageUrl);
string[] downloadFile = await DownloadFiles(enumerable);
}
public static async Task<string[]> DownloadFiles(IEnumerable<string> enumerable)
{
if (enumerable == null) throw new ArgumentNullException("enumerable");
await enumerable.ForEachAsync(5, s => DownloadFile(s));
// Incomplete, the above statement is void and can't be returned
}
public static async Task<string> DownloadFile(string address)
{
/* Download a file from specified address,
* return destination file name on success or null on failure */
if (address == null)
{
return null;
}
Uri result;
if (!Uri.TryCreate(address, UriKind.Absolute, out result))
{
Debug.WriteLine(string.Format("Couldn't create URI from specified address: {0}", address));
return null;
}
try
{
using (var client = new WebClient())
{
string fileName = Path.GetTempFileName();
await client.DownloadFileTaskAsync(address, fileName);
Debug.WriteLine(string.Format("Downloaded file saved to: {0} ({1})", fileName, address));
return fileName;
}
}
catch (WebException webException)
{
Debug.WriteLine(string.Format("Couldn't download file from specified address: {0}", webException.Message));
return null;
}
}
【问题讨论】:
-
完全不清楚您期望的结果是什么。您正在传递整个
T值序列,并对它们执行相同的函数 - 您希望从返回的Task<TResult>中得到什么结果? -
在这种情况下我想获得一个任务
,我在我的问题上添加了一个示例。 -
“使用这种方法我想并行异步下载多个文件” :
Parallel.Foreach还不够吗? -
@Aybe,在你的情况下你希望它是一个
Task<IEnumerable<string>>,或者如果你真的想要Task<string>,你会返回什么字符串? -
@Aybe 我想你还是不明白。假设您正在下载两个页面,一个包含
foo,另一个包含bar。如果您的ForEachAsync()要返回Task<string>,您希望它包含什么字符串?鉴于您的代码,如果它返回Task<string[]>会更有意义。
标签: c# foreach task async-await