如何访问调用异步方法时可用的变量?



动物名称是从API获取的,如果没有找到动物,则返回404。但为了正确记录错误,我们需要进入动物的国家。这可能吗?我从一个叫Stephen Cleary的人那里读到一些东西,让我觉得lambda是可能的,但是我找不到任何东西。

var gettingNames = new List<Task<string>>();
foreach (var animal in animals)
{
gettingNames.Add(this.zooApi.GetNameAsync(animal));
}
try
{
await Task.WhenAll(gettingNames);
}
catch (Exception e)
{
var exception = gettingNames.Where(task => task.IsFaulted)
.SelectMany(x => x.Exception.InnerExceptions).First();
this.logger.LogError("The animal name from {Country} was not found",
animal.Country); // This is the goal
}

解决此问题的一种方法是将每个Animal投影到包含比裸名称或裸错误更多信息的Task。例如,您可以将它投射到包含三条信息的Task<ValueTuple<Animal, string, Exception>>:动物,zooApi中动物的科学名称,以及调用zooApi.GetScientificNameAsync方法时可能发生的错误。

最简单的方法是LINQSelect运算符:

List<Task<(Animal, string, Exception)>> tasks = animals.Select(async animal =>
{
try
{
return (animal, await this.zooApi.GetScientificNameAsync(animal),
(Exception)null);
}
catch (Exception ex)
{
return (animal, null, ex);
}
}).ToList();
(Animal, string, Exception)[] results = await Task.WhenAll(tasks);
foreach (var (animal, scientificName, error) in results)
{
if (error != null)
this.logger.LogError(error,
$"The {animal.Name} from {animal.Country} was not found");
}

你几乎成功了。:)

比起List<Task<string>>,你需要一个Dictionary<Task<string>, string>结构:

static async Task Main()
{
var taskInputMapping = new Dictionary<Task<string>, string>();
var inputs = new[] { "input", "fault", "error", "test"};
foreach (var input in inputs)
{
taskInputMapping.Add(DelayEcho(input), input);
}
try
{
await Task.WhenAll(taskInputMapping.Keys);
}
catch
{
foreach (var pair in taskInputMapping.Where(t => t.Key.IsFaulted))
{
Console.WriteLine($"{pair.Value}: {pair.Key.Exception?.GetType().Name}");
}
}
}
static readonly ImmutableArray<string> wrongInputs = 
ImmutableArray.Create("error", "fault");
static async Task<string> DelayEcho(string input)
{
if (wrongInputs.Contains(input)) throw new ArgumentException();
await Task.Delay(10);
return input;
}
  • taskInputMapping.Add(DelayEcho(input), input):将输入保存在Task本身旁边
  • taskInputMapping.Where(t => t.Key.IsFaulted):遍历出错的任务
  • $"{pair.Value}: {pair.Key.Exception?.GetType().Name}":检索输入+相关错误

我综合了这些答案,得出了这个结论:

var tasks = animals.Select(async animal =>
{
try
{
return await this.zooApi.GetNameAsync(animal);
}
catch (Exception ex)
{
this.logger.LogError(error,
$"The {animal.Name} from {animal.Country} was not found");
return null;
}
});
var results = await Task.WhenAll(tasks);
foreach (var name in results.Where(x => x != null))...

最新更新