score:17
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;
}
}
Source: stackoverflow.com
Related Query
- LINQ query to perform a projection, skipping or wrapping exceptions where source throws on IEnumerable.GetNext()
- Wrapping a complex linq query with a Try-Catch block and catching the correct Exceptions
- Trying to perform a a linq query that joins two tables, has a where clause, and groups the results
- How to perform LINQ query over Enum?
- How to use index/position with Where in LINQ query language?
- Linq query with Array in where clause?
- Linq Query Dictionary where value in List
- Linq Query with a Where clause in an Include statement
- linq to sql query with multiple where parameters
- Where to call .AsParallel() in a LINQ query
- Is there a ODATA query to linq where expression (ODATA to Linq )
- linq query where int ID belongs to List<int>
- Using a LINQ Where query to get only some of the ConfigurationManager.ConnectionStrings
- convert string to DateTime in linq query with where clause?
- Does this LINQ code perform multiple lookups on the original data?
- Where in Query with Array in LINQ
- LINQ WHERE method alters source collection
- Where to find translated Linq to Entity query to Sql
- Using string.compare in a linq query where clause
- LINQ query with a WHERE clause with multiple conditions
- Where can I view LINQ source code?
- Linq query works with null but not int? in where clause
- Is there any way to create a LINQ query as a variable without having the data source (yet)?
- Dynamically Modifying Where Condition in LINQ Query
- Linq to entities - SQL Query - Where list contains object with 2 properties (or more)
- Pass int array in where clause of LINQ Query
- LINQ query where boolean value is true or false
- Simple LINQ query to Delete From DataContext Where ID == ID
- Does order of conditions under where clause in a LINQ query matter
- linq query with dynamic predicates in where clause joined by OR
More Query from same tag
- C#: Using LINQ on a derived iterator class when both the derived class and its base implement IEnumerable
- Unable to cast System.Double to System.Object. LINQ to Entities only supports casting EDM primitive or enumeration types
- LINQ join and group
- Implementing Enumerable.OfType<T> with Type instance argument
- Left outer join with Linq Expressions
- Convert my SQL to LINQ
- Iterate over an IQueryable without calling ToList()
- Lambda expression to grab all values inside a Dictionary
- Select and show only parent node based on child selection
- Change items bool property in a collection if they match/not match the index containing in other list using LINQ
- Accessing attributes on methods using extension method
- Skip part of query if item text is empty
- Multi-line foreach loop in linq / lambda
- Data retrieving from XElemnt using LINQ
- Sort item based on another collection item
- The method 'Where' cannot follow the method 'Select' or is not supported
- Linq query to select nested children
- System.Linq.IQueryable Error
- Find string in a list of strings with 1 character difference
- problem using foreach in linq query result
- How can I get a List<int> from LINQ to XML that produces List<List<int>>?
- LINQ Determine if a property on an object in a collection exists in a different collection
- Use the data context as a method argument in LINQPad
- CS1929 - List<T> does not contain an implementation of Where() (using System.Linq)
- local variable scope in linq anonymous method ( closure)
- Join Tables and Select as List of KeyValuePairs
- Using delete on a LINQ to Sql Data Context with an Interface - 'Interface is not mapped as a table'
- Populate custom List sub class from XML document via LINQ
- Cast Exception in C# Where clause
- Return those records off some parents from which their children's certain property equals a certain value?