Skip to content

procudin/catchable-enumerable

Repository files navigation

Catch extension for LINQ

Extends default LINQ operations with exception handling method.

Nuget Build Status

Motivation

Sometimes there is a situation when we need to perform several consecutive transformations for the original collection. This can be done easily with LINQ.

var source = new[] { "123", "0", null, "1" };
var target = source
    .Select(v => int.Parse(v)) // can throw Exception for incorrect string
    .Select(v => v * 2)
    .ToArray();

But sometimes it's happens that a function called inside a request can throw an exception, which in some cases can be ignored or replaced with default value. However we must write a bunch of boilerplate to handle this exception:

var target = source
    .Select(v => 
        {
            try
            {
                return int.Parse(v);
            }
            catch (Exception)
            {
                return -1; // some default behaviour 
            }
        })
    .Select(v => v * 2)
    .ToArray();

The CatchableEnumerable library takes care of all the work, allowing you to write concise functional code with declarative style:

var target = source.AsCatchable() // move source to catchable context
    .Select(v => int.Parse(v))
    .Catch((Exception e) => { /* some action */ }, () => -1) 
    .Select(v => v * 2)
    .ToArray();

Details

The library uses it's own interface -- ICatchableEnumerable<T>, which is just a wrapper for IEnumerable<T>. It can be created from IEnumerable<T> with AsCatchable() extension method.

var source = Enumerable.Range(0, 5); // typeof(source) == IEnumerable<int>
var target = source.AsCatchable();   // typeof(target) == ICatchableEnumerable<int>

Objects of ICatchableEnumerable<T> can use library-provided extenions for Select, SelectMany and Where operations. This extensions consume and produce ICatchableEnumerable objects, so it is possible to create a chain of exception-safe transformations:

target = target
    .Select(i => {
        if (i == 2)
            throw new ArgumentException("2");
        return i;
    })
    .Where(i => {
        if (i == 3)
            throw new NotImplementedException("3");
        return true;
    });

Finally you can handle exceptions with Catch extension method:

var handledTarget = target
    .Catch((ArgumentException ex) => { })                  // skip problem item
    .Catch((NotImplementedException ex) => { }, () => -3); // replace it with default one
string.Join(",", target); // "0,1,-3,4"

Note that the order of the Catch methods is important. If the type of the handled exception is wider than folowing onces, they won't be handled:

var handledTarget = target
    .Catch((ArgumentException ex) => { })  
    .Catch((Exception ex) => { })           // wider than folowing
    .Catch((NotImplementedException ex) => { /* will never be called */ }, () => -3);
string.Join(",", target); // "0,1,4"

About

Implementation of Catch function for LINQ

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages