使用 LINQ 时捕获更有用的异常/诊断



就像我喜欢 C# 中的 lambda 表达式/LINQ 一样,我似乎不时会遇到同样的问题,并希望获得一些有关如何最好地处理以下类型场景的指示。

下面的代码纯粹是示例,希望能演示我想要实现的目标:

public class Program
{
    public class Demo
    {
        public string Name { get; set; }
        public string Val { get; set; }
    }
    public class Test
    {
        public string Name { get; set; }
        public int Val { get; set; }
    }
    public static void Main()
    {
            List<Demo> list = new List<Demo> { 
                new Demo { Name = "First", Val = "1" }, 
                new Demo { Name = "Second", Val = "2" }, 
                new Demo { Name = "Third" } 
            };
        // Obviously this will blow up as my last item in 'list' has a null 'Val' property
        try {
            List<Test> results = list.Select(l => new Test { Name = l.Name, Val = int.Parse(l.Val) }).ToList();
        } 
        catch(Exception x)
        {
            // I want some generic way of capturing a better fault here in my log - e.g. more details about the actual item in my collection would be useful!
            Log.Error("Something broke", x, this);
        }
    }
}

链接到代码笔示例

上面的代码可能会记录异常,例如:

运行时异常(第 48 行):值不能为空。参数名称: 字符串

堆栈跟踪:

[System.ArgumentNullException:值不能为空。参数名称: 字符串] 在 Program.b__5(演示 l): 第 48 行在 Program.Main(): 48号线

所以我知道我可以捕获x.Message、堆栈跟踪等,但我的观点是,当处理大型/复杂数据集时(特别是当数据来自生产环境中的另一个系统等时),可能很难跟踪导致异常的集合中的实际数据/项目。

是否有一种整洁/通用(无双关语)的方式来处理此类场景?

这样

想。如果不使用 Linq,则代码类似于:

public List<Test> DemoToTestProjection(List<Demo> demos)
{
    var projectedTests = new List<Test>();
    for each (var demo in demos)
    {
        projectedTests.Add(new Test
        {
            Name = l.Name,
            Val = int.Parse(l.Val)
        });
    }
    return projectedTests;
}
public void DoSomething()
{
    var demos = new List<Demo>({...});
    try
    {
        var result = DemoToTestProjection(demos);
    }
    catch(Exception ex)
    {
        // How would you expect to get information about the specific
        // `Demo` you were having an issue with here?
    }
}

答案是,您需要将尝试/捕获放在您想要详细日志记录的位置周围。

因此,如果你想要这种级别的日志记录,你可以通过创建一个不同的方法来执行投影,并在那里添加你的日志记录:

var = list.Select(l => MapToTest(l))
          .ToList();
public Test MapToTest(Demo demo)
{
    try
    {
        Test test = new Test {...};
    }
    catch(Exception ex)
    {
        LogStuffAboutDemo(demo);
    }
}

或者(丑陋),内联:

var = list.Select(l =>
          {
              try {...}
              catch{ LogStuffAboutDemo(l); }
          })
          .ToList();

最新更新