LINQ method chain and granular error handling

I have a method that can be written fairly neatly through a chain of methods:

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

However, I would like to be able to do some checks at every point, because I want to provide useful diagnostic information if any of the chained methods returns unexpected results.

To achieve this, I need to break the whole chain and complete each call with an if block. This makes the code much less readable.

Ideally, I would like to be able to interlace calls with chains that allow me to handle unexpected results at each point (for example, throw a meaningful exception such as new ConventionException("The report contains no parameter") if the first method returns an empty collection). Can anyone suggest an easy way to achieve this?

Edit:

This is the result of using @JeffreyZhao's answer:

 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"); 
+6
source share
3 answers

Perhaps you can use this approach.

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

then

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

Update:

You can even:

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

then

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

You can easily divide the process into separate steps with local variables:

 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; 

Now you can perform any checks between steps.

Please note, however, that some results do not actually work. The last step, for example, does not lead to the result of the list, it returns an enumerated value that is read from ValidValues , so any errors at this stage will occur when you use the result, and not inside this method. You might want to add .ToList() at the end of some steps to implement the result.

+1
source

Consider using Code Contracts (for example, add a post-condition to ServerReport.GetParameters to ensure that methods do not return an empty collection). They let you do what you want in a more elegant way than writing your own validation logic.

 class ReportParameter { } class ServerReport { public ReportParameter[] GetParameters() { Contract.Ensures(Contract.Result<ReportParameter[]>() != null && Contract.Result<ReportParameter[]>().Length > 0, Resource1.Oops); // here some logic to build parameters array... return new ReportParameter[0]; } } 

Using:

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

Source: https://habr.com/ru/post/917510/


All Articles