score:4

Accepted answer

Here is the simplest change you can make to simply exclude items which are null or are raising an exception.

tmpLst = App.lstAllChilds.Where(e =>
{
    try
    {
        return e != null && e.Id == Id;
    }
    catch
    {
        return false;
    }
}).ToList();

But in my opinion you probably should investigate and solve the underlying problem. This doesn't seem like a scenario where exceptions should be expected.

score:2

It depends what exactly you are trying to achieve:

  1. Return the list except "broken" items.

    • You can try using a Where clause to check and filter them out:

      App.lstAllChilds.Where(x => IsValidNode(x, Id)).ToList();
      

      Apparently you need to implement IsValidNode which should check for null, if it can throw an InvalidObjectException (not sure if you can easily detect it but you can always wrap it in a try-catch block) and Id equality. Like that:

      private bool IsValidNode(Child c, int id)
      {
          if (x == null) return false;
          try {
              return c.Id == id;
          }
          catch (InvalidObjectException)
          {
      
          }
          return false;
      }
      
  2. Return an empty list if there are any broken items.

    • Just wrap the entire thing in a try-catch block

score:11

In case if you just want to ignore "bad elements" then:

App.lstAllChilds.SkipExceptions().Where( e => e.Id == Id).ToList();

Extension method:

 public static class Extensions
    {
        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;
                }
            }
        }
    }

score:3

So, here's the thing. There's language integrated query (Linq), and then there's yielded enumeration (a.k.a. Iterators).

Linq allows you to define an expression tree that is later executed by something that may or may not be C# (for example the expression could be translated into a SQL query). If you're writing linq there is a good chance your query provider (the thing that does the expression translation) does not support exception handling (much less whatever you're doing that throws exceptions).

Interators on the other hand (or "linq to objects") just ends up executing in C#, so you can just go wild with your exception handling.

For example w/ linq to objects you can do this:

var myList = new[] { "1", "2", "BARF", "3" };
var sum = myList.Select(str => {
  try {
    return Int32.Parse(str);
  } catch {
    return 0;
  }
}).Aggregate((x, y) => x + y);

If you're indeed doing linq to objects, and you just want to skip elements where your source IEnumerable threw an exception check out Vladimir Gondarev's answer.

The important thing to understand however, is that the anonymous function we just passed to that Select call is not an Expression (an uncompiled expression tree), it is a Func (a delegate pointing to compiled c# code), which means that it will run in the .Net process, even if we replaced myList with a linq to entities table (or some other linq provider). The reason for this is that the C# expression syntax does not support blocks, nor does it support try-catch. Unsurprisingly, given that, the SQL-style Linq statements (from xxx select yyy) also do not support try-catch blocks.

However, just because the C# expression syntax doesn't support it doesn't mean you can't do it. But, to be clear, I do not recommend doing this because I highly doubt there is a QueryProvider in existence that supports it (aside from the linq to objects provider). For the curious here's how you would create a lambda expression that contains a try-catch block.

var parseMethod = typeof(Int32).GetMethod("Parse", new[] { typeof(String) });
var param = Expression.Parameter(typeof(String));
var selectExp =
    Expression.Lambda<Func<String, Int32>>(
        Expression.TryCatch(
            Expression.Call(parseMethod, param),
            Expression.Catch(typeof(Exception), Expression.Constant(0))
        ),
        param
    );
var sum = myList.Select(selectExp).Aggregate((x, y) => x + y);

So when somebody implements a QueryProvider backed by a store that supports exception handling, you could use this.


Related Articles