2012-06-07 13 views
6

我有这可以通过方法链接很整齐地写一个方法:LINQ方法链和精细错误处理

return viewer.ServerReport.GetParameters() 
    .Single(p => p.Name == Convention.Ssrs.RegionParamName) 
    .ValidValues 
    .Select(v => v.Value); 

但是我希望能够做一些检查,在每一个点,我想如果任何链式方法返回意外结果,则提供有用的诊断信息。

为了实现这个目标,我需要分解我所有的链接,并按照if块的方式跟随每个呼叫。它使代码更不易读。

理想情况下,我希望能够编织一些链接的方法调用,这将允许我在每个点处理意外的结果(例如,如果第一个方法返回空集合,则抛出一个有意义的异常,例如new ConventionException("The report contains no parameter"))。任何人都可以提出一个简单的方法来实现这样的事情?

编辑:

这是使用@ JeffreyZhao的回答结果:

return viewer.ServerReport.GetParameters() 
    .Assert(result => result.Any(), "The report contains no parameter") 
    .SingleOrDefault(p => p.Name == Convention.Ssrs.RegionParamName) 
    .Assert(result => result != null, "The report does not contain a region parameter") 
    .ValidValues 
    .Select(v => v.Value) 
    .Assert(result => result.Any(), "The region parameter in the report does not contain any valid value"); 

回答

7

也许你可以使用这种方法。

static T Check<T>(this T value) 
{ 
    if (...) throw ...; 

    return value; 
} 

则:

xxx.Single(...).Check().Select(...).Check()... 

更新:

你甚至可以:

static T Validate<T>(this T value, Func<T, bool> validate, string errorMessage) 
{ 
    if (!validate(value)) 
     throw new ValidationFailedException(errorMessage); 

    return value; 
} 

则:

xxxx.Single() 
    .Validate(v => v > 0, "Must be greater than zero") 
    .NextStep() 
    .Validate(...); 
+0

这看起来不错。考虑到错误检查的本质,我怀疑它可能不需要泛型方法(即通常错误检查的性质是特定于给定类型的)。有一个扩展方法只是返回未经修改的输入的一般方法正是需要的。 – Chris

+0

你说得对。我添加了一个更通用的'Validate'方法,在这种情况下,泛型是必需的。 –

+0

不错。我希望我可以再次为这个不错的小验证功能+1。 :) – Chris

1

您可以在单独的步骤与局部变量容易裂开的过程:

var result1 = viewer.ServerReport.GetParameters(); 
var result2 = result1.Single(p => p.Name == Convention.Ssrs.RegionParamName); 
var result3 = result2.ValidValues; 
var result4 = result3.Select(v => v.Value); 
return result4; 

现在,你可以做你想做的步骤之间的任何检查。

但请注意,某些结果实际上并未做任何工作。举例来说,最后一步不会产生一个列表作为结果,它会产生一个从ValidValues中读取的枚举值,所以在使用结果时会发生该步骤中的任何错误,而不是在此方法内。在某些步骤结束时,您可能需要添加.ToList()以实现结果。

1

考虑使用Code Contracts(例如,为ServerReport.GetParameters添加后续条件以确保方法不会返回空集合)。他们允许以更优雅的方式做你想做的事情,而不是写自己的检查逻辑。

class ReportParameter { } 
class ServerReport 
{ 
    public ReportParameter[] GetParameters() 
    { 
     Contract.Ensures(Contract.Result<ReportParameter[]>() != null && Contract.Result<ReportParameter[]>().Length > 0, 
      Resource1.Oops); 

     // here's some logic to build parameters array... 
     return new ReportParameter[0]; 
    } 
} 

用法:

// Oops! I need at least one parameter! 
var parameters = new ServerReport().GetParameters(); 
+0

这听起来很理想。但在我的特殊情况下,数据需要符合某些期望,所以静态分析无法帮助(但我意识到这也提供了运行时检查,但不确定采用这种新方法并使用新工具在我的给予这种情况)。当条件不满意时,我能够注入自己的逻辑吗?我真的需要更多地关注这个! – Clafou

+0

我的意思是允许我提供有用的特定异常而不是泛型异常类型的逻辑,从而使我的调用代码更容易处理可恢复的错误。 – Clafou

+0

@Clafou,你想要注入什么逻辑之王?违反合同会带来一个'ContractException'。你可以解决的。 – Dennis