5

注意:请参阅底部的编辑。我是一个白痴。

以下代码来处理一组标签名称并识别/处理新的:

IEnumberable<string> tagNames = GetTagNames();
List<Tag> allTags = GetAllTags();

var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name == n));

foreach (var tagName in newTagNames)
{
    // ...
}

...这很好,除了它无法处理有一个名为“Foo”的标签并且列表包含“foo”的情况。换句话说,它没有进行不区分大小写的比较。

我将测试更改为使用不区分大小写的比较,如下所示:

var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.Equals(n, StringComparison.InvariantCultureIgnoreCase)));

...当foreach 运行(并调用MoveNext)newTagNames 时突然抛出异常。异常说:

序列没有元素

我对此感到困惑。为什么要foreach坚持序列非空?如果我正在调用First(),我希望看到该错误,但在使用时不会foreach


编辑:更多信息。

这正在变得越来越奇怪。因为我的代码在异步方法中,而且我很迷信,所以我认为在引发异常的点与捕获和报告异常的点之间存在太多的“距离”。因此,我在有问题的代码周围放置了一个 try/catch,希望验证抛出的异常是否真的是我认为的那样。

所以现在我可以在调试器中单步执行 foreach 行,我可以验证序列是否为空,并且我可以单步执行调试器突出显示单词“in”的位置。再迈一步,我就在我的异常处理程序中。

但是,不是我刚刚添加的异常处理程序,不!它位于我最外层的异常处理程序中,而无需访问我最近添加的异常处理程序!它不匹配catch (Exception ex),也不匹配普通的catch. (我也确实放入了一个finally, 并验证它确实会在出路时访问它)。

我一直相信这样的异常处理程序会捕获任何异常。我现在很害怕。我需要一个成年人。


编辑 2

好的,所以嗯,误报......我的本地 try/catch 没有捕获到异常,只是因为它没有被我认为的代码引发。正如我上面所说,我看到调试器中的执行从直接的“in”跳转foreach到外部异常处理程序,因此我的(错误)假设是错误所在。但是,对于空枚举,这只是函数内执行的最后一条语句,并且由于某种原因,调试器没有向我显示函数的步骤或在调用点执行下一条语句 - 这是在事实上导致错误的那个。

向所有回复的人道歉,如果您想创建一个说我是白痴的答案,我很乐意接受。也就是说,如果我再次在 SO 上露脸……

4

2 回答 2

0

它不是那么正确或干净,但它是如何工作的:

var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.ToUpper() == n.ToUpper()));
于 2012-11-14T17:57:43.710 回答
0

延迟操作的异常处理很有趣。在枚举查询之前,不会执行 Enumerable.Where 方法(和大多数 linq 方法)。

IEnumerable<int> query = Enumerable.Empty<int>();
int myNum = 0;
try
{
  query = Enumerable.Range(1, 100).Where(i => (i/myNum) > 1);
}
catch
{
  Console.WriteLine("I caught divide by zero"); //does not run
}

foreach(int i in query) //divide by zero exception thrown
{
  //..
}

在您的特定情况下:

IEnumberable<string> tagNames = GetTagNames();

我敢打赌GetTagNames,里面有一个 Enumerable.First 或 Enumerable.Single。如果 GetTagNames 的结果被延迟,您必须枚举该结果以使异常发生。这就是为什么评论者建议您在 GetTagNames 的结果上调用 ToList - 枚举它并在复杂查询中使用 tagNames 之前发生异常。

于 2012-11-14T19:59:36.170 回答