就像我喜欢 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();