user1675891
user1675891

Reputation:

Converting for-loop to LINQ

If I have the following working code:

List<MyClass> results = new List<MyClass>();

for(int i = 0; i < source.Count; i++)
  try{ results.Add(Fetch(source[i])); }
  catch(Exception ex){ results.Add(new MyClass("poof!")); }
...
public MyClass Fetch(Object source){ ... }

and would like to remake it into LINQ, how can I manage the try-catch? If I put it around the following expression, It's not going to poof me. My suggestion would be to migrate catching into the method but I'm not sure how optimal/recommended that is. Can one tell at all or is depending on specifics of the scenario?

IEnumerable<String> strings = source.Select(e => Fetch(e));

public MyClass Fetch(Object source){ try{ ... } catch(){ ... } }

It'd be cool with something like this pseudo-code. I'm thinking the method .First() and it's more-potent brother .FirstOrDefault(), but with additional capacity.

IEnumerable<String> strings = source.Select(e => Fetch(e)).Excepted(...);

Am I way off?

Upvotes: 1

Views: 112

Answers (4)

Jens
Jens

Reputation: 25563

You'd get the same behaviour as your original code from

List<String> results = source.Select(e => { try
                                            {
                                                return Fetch(e);
                                            }
                                            catch(Exception)
                                            {
                                                 return MyClass("poof");
                                            }
                                          }).ToList();

But I think you should reconsider using try/catch this way. It has a severe performance cost, and is not intended to handle non-exceptional cases. Better check first if e is fetchable and do something like

List<String> results = source.Where(e => IsFetchable(e))
                             .Select(e => Fetch(e))
                             .ToList();

Upvotes: 0

JaredPar
JaredPar

Reputation: 754813

Your best bet is to move the try / catch block into a separate method and use that method as the selector.

public MyClass FetchOrDefault(object source){ 
  try { 
    return Fetch(source);
  } catch (Exception ex) { 
    return new MyClass("poof");
  }
}

// Method call syntax
var e = source.Select(x => x.FetchOrDefault(x));

// LINQ syntax
var e = from x in source select FetchOrDefault(x);

Upvotes: 2

Servy
Servy

Reputation: 203833

I don't think you'll be able to create your Excepted class, but you can create a Select method with two selectors, one for the error case:

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source,
    Func<TSource, TResult> selector, Func<TSource, TResult> secondarySelector)
{
    foreach (var item in source)
    {
        TResult nextValue;
        try
        {
            nextValue = selector(item);
        }
        catch
        {
            nextValue = secondarySelector(item);
        }

        yield return nextValue;
    }
}

Then it would allow you to do:

var results = source.Select(item => Fetch(item)
    , item => new MyClass("poof!"))
    .ToList();

Your secondary selector could also take the exception as a parameter, if that would be appropriate.

Upvotes: 0

Stan R.
Stan R.

Reputation: 16065

The easiest solution is to just do what you did already i.e. you can include code block.

IEnumerable<String> strings = source.Select(e =>
{
try
  {
    return Fetch(e);
  }
catch
 {
    return new MyClass("poof");
 }
}
);

Upvotes: 0

Related Questions