在 lambda 中引发的异常未被 catch 块捕获 [duplicate]

Exception thrown within lambda not caught by catch block [duplicate]

提问人:Rachel 提问时间:8/25/2023 更新时间:8/25/2023 访问量:40

问:

我已经看到了一些关于 lambda 和异常的问题,但我仍然不明白我在代码中看到的行为。

        class MyObj
        {
            public object Prop1 { get; set; }
        }

        public void Get()
        {
            try
            {
                IEnumerable<MyObj> collection = new List<MyObj>() { new MyObj() };
                collection = collection.Where(x =>
                {
                    return x.Prop1.ToString() == "some value";
                });
            }
            catch (Exception ex)
            {
                throw new UriFormatException($"Invalid filter. Error details: {ex.Message}");
            }
        }

由于为 null,因此会引发“对象引用未设置为对象的实例”异常。但是,代码不会进入块。如果我添加更多尝试在块中使用的代码,则当 lambda 中遇到异常时,将输入该块。例如Prop1catchcollectiontrycatch

                foreach (var c in collection)
                {
                    Console.WriteLine(c);
                }

如果在执行 lambda 时出现任何异常,我希望输入 catch 块。我尝试编写一个命名函数以从 lambda 调用,这也不起作用。我错过了什么?

C# Lambda Try-catch NullReferenceException

评论


答:

1赞 StriplingWarrior 8/25/2023 #1

LINQ 运算符喜欢使用称为“延迟执行”的东西。这意味着,当您调用它们时,它们实际上并没有执行您提供给它们的 lambda:它们只是返回一个跟踪 lambda 和源的新查询。然后,当您尝试执行该查询时,它将开始评估 lambda。Where

这可能是有益的,因为如果您最终在查询末尾放置了类似 a 或 a 的内容,则可以避免对集合中的每个项目运行委托。但由于各种原因,它可能会有问题:如果同一个查询被多次执行,它将重复大量工作;如果 Lambda 中捕获的值在执行之前发生更改,则可以有意义地更改查询的行为.First().Take(10)

因此,如果你想捕获查询委托中抛出的异常,你要么需要在 foreach 循环周围放置一个 try/catch,要么在其中放置类似 a 的东西来强制立即执行。.ToList()

            try
            {
                var collection = new List<MyObj>() { new MyObj() }
                    .Where(x =>x.Prop1.ToString() == "some value")
                    .ToList();
            }
            catch (Exception ex)
            {
                throw new UriFormatException($"Invalid filter. Error details: {ex.Message}");
            }