【发布时间】:2013-11-23 05:31:03
【问题描述】:
当您不总是想返回结果时,我一直在尝试寻找一种“干净”的模式来处理具有匿名类型的 .SelectMany。我最常见的用例如下所示:
- 我们有一份我想要报告的客户列表。
- 每个客户的数据都驻留在一个单独的数据库中,所以我做了一个并行
.SelectMany - 在每个 lambda 表达式中,我为客户收集结果以形成最终报告。
- 如果应该跳过特定客户,我需要返回一个空列表。
- 我经常使用这些来快速报告,所以我更喜欢匿名类型。
例如,逻辑可能如下所示:
//c is a customer
var context = GetContextForCustomer(c);
// look up some data, myData using the context connection
if (someCondition)
return myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 });
else
return null;
这可以作为一个 foreach 语句来实现:
var results = new List<WhatType?>();
foreach (var c in customers) {
var context = GetContextForCustomer(c);
if (someCondition)
results.AddRange(myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 }));
}
或者它可以使用.SelectMany 来实现,该.Where 预先过滤:
customers
.Where(c => someCondition)
.AsParallel()
.SelectMany(c => {
var context = GetContextForCustomer(c);
return myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 });
})
.ToList();
这两种方法都存在问题。 foreach 解决方案需要初始化一个List 来存储结果,并且您必须定义类型。 .SelectMany 和.Where 通常是不切实际的,因为someCondition 的逻辑相当复杂并且依赖于一些数据查找。所以我理想的解决方案应该是这样的:
customers
.AsParallel()
.SelectMany(c => {
var context = GetContextForCustomer(c);
if (someCondition)
return myData.Select(x => new { CustomerID = c, X1 = x.x1, X2 = x.x2 });
else
continue? return null? return empty list?
})
.ToList();
我应该在else 行中添加什么来跳过返回值?我能想出的解决方案都不是有效的或理想的:
-
continue无法编译,因为它不是活动的foreach循环 -
return null导致NRE -
return空列表需要我重新初始化一个匿名类型的列表。
有没有一种方法可以干净、简单、整洁,并满足我所有(挑剔的)要求?
【问题讨论】:
标签: c# anonymous-types linq