2012-06-07 2 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"), если первый метод возвращает пустую коллекцию). Может ли кто-нибудь предложить простой способ достичь такого?

Edit:

Это результат использования @ ответ 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()... 

Update:

Вы даже можете:

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

Ницца. Мне жаль, что я не смогу еще раз повторить эту приятную маленькую функцию 'Validate'. :) – 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

@ Клаф, какой король логики вы хотите вставить? Нарушение договора приводит к «КонтрактуException». Вы можете справиться с этим. – Dennis