score:17

Accepted answer

How about this (you might want to give this special Select Extension a better name)

public static IEnumerable<TOutput> SelectIgnoringExceptions<TInput, TOutput>(
    this IEnumerable<TInput> values, Func<TInput, TOutput> selector)
   {
        foreach (var item in values)
        {
            TOutput output = default(TOutput);

            try
            {
                output = selector(item);
            }
            catch 
            {
                continue;
            }

            yield return output;
        }
    }

Edit5 Added a using statement, thanks for the suggestion in comments

    public static IEnumerable<T> SkipExceptions<T>(
        this IEnumerable<T> values)
    {
        using(var enumerator = values.GetEnumerator())
        {
           bool next = true;
           while (next)
           {
               try
               {
                   next = enumerator.MoveNext();
               }
               catch
               {
                   continue;
               }

               if(next) yield return enumerator.Current;
           } 
        }
    }

However this relies on the incoming IEnumerable not already being created (and therefore already having thrown Exceptions) as a list by the preceding Function. E.g. this would probably not work if you call it like this: Select(..).ToList().SkipExceptions()

score:-1

You could just chain the Where and Select method together.

var numbers = strings.Where(s =>
                      {
                          int i;
                          return int.TryParse(s, out i);
                      }).Select(int.Parse);

The use of the Where method effectively removes the need for you to write your own SkipExceptions method, because this is basically what you are doing.

score:0

This is the same answer as Thomas's, but with a lambda & LINQ expression. +1 for Thomas.

Func<string, int?> tryParse = s =>
{
    int? r = null;
    int i;
    if (int.TryParse(s, out i))
    {
        r = i;
    }
    return r;
};

var ints =
    from s in strings
    let i = tryParse(s)
    where i != null
    select i.Value;

score:1

Here's a small complete program to demonstrate an answer inspired by the maybe monad. You might want to change the name of the 'Maybe' class, as it is inspired by rather than actually being a 'Maybe' as defined in other languages.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestMaybe
{
    class Program
    {
        static void Main(string[] args)
        {
            var strings = new string[] { "1", "2", "notint", "3" };
            var ints = strings.Select(s => new Maybe<string, int>(s, str => int.Parse(str))).Where(m => !m.nothing).Select(m => m.value);
            foreach (var i in ints)
            {
                Console.WriteLine(i);
            }
            Console.ReadLine();

        }
    }

    public class Maybe<T1, T2>
    {
        public readonly bool nothing;
        public readonly T2 value;

        public Maybe(T1 input, Func<T1, T2> map)
        {
            try
            {
                value = map(input);
            }
            catch (Exception)
            {
                nothing = true;
            }            
        }
    }
}

Edit: depending on the needs of your code, you might also want nothing set to true if the result of map(input) is null.

score:2

Even the accepted answer may not be "general" enough. What if some day you find that you need to know what exceptions occurred?

The following extension

static class EnumeratorHelper {

    //Don't forget that GetEnumerator() call can throw exceptions as well.
    //Since it is not easy to wrap this within a using + try catch block with yield,
    //I have to create a helper function for the using block.
    private static IEnumerable<T> RunEnumerator<T>(Func<IEnumerator<T>> generator, 
        Func<Exception, bool> onException)
    {
        using (var enumerator = generator())
        {
            if (enumerator == null) 
                yield break;
            for (; ; )
            {
                //You don't know how to create a value of T,
                //and you don't know weather it can be null,
                //but you can always have a T[] with null value.
                T[] value = null;
                try
                {
                    if (enumerator.MoveNext())
                        value = new T[] { enumerator.Current };
                }
                catch (Exception e)
                {
                    if (onException(e))
                        continue;
                }
                if (value != null)
                    yield return value[0];
                else
                    yield break;
            }
        }
    }

    public static IEnumerable<T> WithExceptionHandler<T>(this IEnumerable<T> orig, 
        Func<Exception, bool> onException)
    {
        return RunEnumerator(() =>
        {
            try
            {
                return orig.GetEnumerator();
            }
            catch (Exception e)
            {
                onException(e);
                return null;
            }
        }, onException);
    }

}

will help. Now you can add SkipExceptions:

 public static IEnumerable<T> SkipExceptions<T>(this IEnumerable<T> orig){
     return orig.WithExceptionHandler(orig, e => true);
 }

By using different onException callback, you can do different things

  • Break the iteration but ignore the exception: e => false
  • Try to continue iteration: e => true
  • Log the exception, etc

score:7

Create a TryParseInt method that returns a Nullable<int>:

int? TryParseInt(string s)
{
    int i;
    if (int.TryParse(s, out i))
        return i;
    return null;
}

And use it in your query like that:

var numbers = strings.Select(s => TryParseInt(s))
                     .Where(i => i.HasValue)
                     .Select(i => i.Value);

See also this article by Bill Wagner, which presents a very similar case.


Now, i don't think you can write something like a generic SkipExceptions method, because you would catch the exception too late, and it would end the Select loop... But you could probably write a SelectSkipException method:

public static IEnumerable<TResult> SelectSkipExceptions<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, TResult> selector)
{
    if (source == null)
        throw new ArgumentNullException("source");
    if (selector == null)
        throw new ArgumentNullException("selector");
    return source.SelectSkipExceptionsIterator(selector);
}

private static IEnumerable<TResult> SelectSkipExceptionsIterator<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, TResult> selector)
{
    foreach(var item in source)
    {
        TResult value = default(TResult);
        try
        {
            value = selector(item);
        }
        catch
        {
            continue;
        }
        yield return value;
    }
}

Related Query

More Query from same tag