Search code examples
c#linqchainingmethod-chaining

LINQ method chaining and granular error handling


I have a method which can be written pretty neatly through method chaining:

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

However I'd like to be able to do some checks at each point as I wish to provide helpful diagnostics information if any of the chained methods returns unexpected results.

To achieve this, I need to break up all my chaining and follow each call with an if block. It makes the code a lot less readable.

Ideally I'd like to be able to weave in some chained method calls which would allow me to handle unexpected outcomes at each point (e.g. throw a meaningful exception such as new ConventionException("The report contains no parameter") if the first method returns an empty collection). Can anyone suggest a simple way to achieve such a thing?

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");

Solution

  • Maybe 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(...);