我正在将 Excel 电子表格转换为“元素”列表(这是一个领域术语)。在此转换期间,我需要跳过标题行并丢弃无法转换的格式错误的行。
有趣的来了。我需要捕获那些格式错误的记录,以便我可以报告它们。我构建了一个疯狂的 LINQ 语句(如下)。这些是隐藏 OpenXml 库中类型的凌乱 LINQ 操作的扩展方法。
var elements = sheet
.Rows() <-- BEGIN sheet data transform
.SkipColumnHeaders()
.ToRowLookup()
.ToCellLookup()
.SkipEmptyRows() <-- END sheet data transform
.ToElements(strings) <-- BEGIN domain transform
.RemoveBadRecords(out discard)
.OrderByCompositeKey();
有趣的部分从 开始ToElements
,我将行查找转换为我的域对象列表(详细信息:它称为 an ElementRow
,后来转换为 an Element
)。不良记录仅使用一个键(Excel 行索引)创建,并且与真实元素相比是唯一可识别的。
public static IEnumerable<ElementRow> ToElements(this IEnumerable<KeyValuePair<UInt32Value, Cell[]>> map)
{
return map.Select(pair =>
{
try
{
return ElementRow.FromCells(pair.Key, pair.Value);
}
catch (Exception)
{
return ElementRow.BadRecord(pair.Key);
}
});
}
然后,我想删除那些不良记录(在过滤之前收集所有这些记录更容易)。那个方法是RemoveBadRecords
,它是这样开始的......
public static IEnumerable<ElementRow> RemoveBadRecords(this IEnumerable<ElementRow> elements)
{
return elements.Where(el => el.FormatId != 0);
}
但是,我需要报告丢弃的元素!而且我不想用报告混淆我的转换扩展方法。所以,我去了 out 参数(考虑到在匿名块中使用 out 参数的困难)
public static IEnumerable<ElementRow> RemoveBadRecords(this IEnumerable<ElementRow> elements, out List<ElementRow> discard)
{
var temp = new List<ElementRow>();
var filtered = elements.Where(el =>
{
if (el.FormatId == 0) temp.Add(el);
return el.FormatId != 0;
});
discard = temp;
return filtered;
}
而且,瞧!我以为我是铁杆,并且会一口气完成此操作...
var discard = new List<ElementRow>();
var elements = data
/* snipped long LINQ statement */
.RemoveBadRecords(out discard)
/* snipped long LINQ statement */
discard.ForEach(el => failures.Add(el));
foreach(var el in elements)
{
/* do more work, maybe add more failures */
}
return new Result(elements, failures);
但是,discard
当我循环浏览它时,我的列表中没有任何内容!我单步执行了代码并意识到我成功地创建了一个全流式 LINQ 语句。
- 临时列表已创建
- 过滤器
Where
已分配(但尚未运行) - 并且分配了丢弃列表
- 然后流媒体的东西被退回
当discard
被迭代时,它不包含任何元素,因为元素还没有被迭代。
有没有办法使用我构建的东西来解决这个问题?我是否必须在坏记录过滤器之前或期间强制迭代数据?还有其他我错过的结构吗?
一些评论
乔恩提到任务/正在/发生。我只是没有等待它。如果我检查 的discard
迭代后的内容elements
,它实际上是完整的!所以,我实际上没有分配问题。除非我接受 Jon 关于 LINQ 语句中好/坏的建议。