Is there a way to return only function calls that do not throw exceptions from LINQ?

I am thrown into an existing codebase, and part of the job is to gradually test the code when I make updates. Thus, it is the process of accepting something old and ugly and makes it more enjoyable.

In this case, there is code similar to this:

foreach (var thingamajigLocator in thingamajigLocators) { Thingamajig thingamajig; try { thingamajig = thingamajigservice.GetThingamajig(thingamajigLocator); } catch { // exception logged further down, but is rethrown continue; } thingamajigCollection.Add(thingamajig); } 

This is ugly and theoretically, if the exception is handled further down, you do not need to handle it here, but like the code at present, it works too much to process the service code.

I would like to do something like this:

 thingamajigCollection = thingamajigLocators .Select(tl => thingamajigservice.GetThingamajig(tl)) .Where( /* some condition that strips out the ones throwing exceptions */ ); 

Is this possible anyway? Any other suggestions? I can of course leave foreach with try / catch, but it seems like it might be more elegant since I don't care what the actual exception is in this case. Which again, I know, this is a terrible form, and it will need to be solved, but now it does not have time.

+4
source share
6 answers

Actually, there is no difference. Func is just a delegate. So you can do it very simply:

 thingamajigCollection = thingamajigLocators .Select(tl => { try { return thingamajigservice.GetThingamajig(tl); } catch(Exception) { return null; } }) .Where(t1 => t1!=null); 

As an option, you can wrap GetThingamajig in a new method to catch exceptions there.

NOTE. As hmemcpy says swallowing exceptions is not the best way. So, you better try to remake things.

+2
source

I wonder how exactly your exceptions are handled above if you swallow and essentially ignore the exceptions coming from your service locators.

Instead of catching and swallowing an exception, I would execute a null object template by returning NullThingamajig from your service locators in case of an error. Then you can simply use the following query to filter the results:

 var thingamajigs = thingamajigCollection.OfType<Thingamajig>(); 

EDIT

If you cannot change the service locators yourself, add them to the proxy object, which will catch the exception and return a null object for you:

 public class ThingamajigLocatorProxy : IThingamajigLocator { private readonly IThingamajigLocator locator; public ThingamajigLocatorProxy(IThingamajigLocator locator) { this.locator = locator; } public Thingamajig Locate() { try { return locator.Locate(); } catch { // log exception return new NullThingamajig(); } } } 

Then you can use the full query below:

 var thingamajig = thingamajigLocators .Select(locator => service.GetThingamajig(new ThingamajigLocatorProxy(locator))) .OfType<Thingamajig>(); 
+2
source

How about the method as follows:

 public IEnumerable<Thingamajig> GetThingamajigs() { foreach (var thingamajigLocator in thingamajigLocators) { Thingamajig thingamajig; try { thingamajig = thingamajigservice.GetThingamajig(thingamajigLocator); } catch { // exception logged higher up // (how can this be? it just got swallowed right here) continue; } yield return thingamajig; } } 

The returned IEnumerable can then be used in the Linq expression, and the intent of the source code is not hidden in too much abstraction.

+2
source

If you want to go a little over the top to pretty cleanly ignore excrement, like "something happens line by line:

 thingamajigCollection = thingamajigLocators .Select(tl => F.Try(()=> thingamajigservice.GetThingamajig(tl))) .Where(thing=>thing.HasValue) .Select(thing=>thing.Value) 

With the following static helper class F :

 public static Maybe<T> Try<T>(Func<T> f) { try { return Maybe<T>.FromValue(f()); } catch (Exception e) { return Maybe<T>.FromException(e); } } public struct Maybe<T> { readonly T val; readonly Exception e; Maybe(T val, Exception e) { this.val = val; this.e = e; } public bool HasValue { get { return e == null; } } public T Value { get { if (!HasValue) throw new InvalidOperationException("Attempted to get a value with an error", e); else return val; } } public static Maybe<T> FromException(Exception e) { return new Maybe<T>(default(T), e); } public static Maybe<T> FromValue(T val) { return new Maybe<T>(val, null); } } 
+2
source

You can have a static helper method that does what you want:

 public static KeyValuePair<T, Exception> TryExecute<T>(Func<T> func) { try { return new KeyValuePair<T, Exception>(func(), null); } catch (Exception ex) { return new KeyValuePair<T, Exception>(default(T), ex); } } thingamajigCollection = thingamajigLocators .Select(tl => TryExecute(() => thingamajigservice.GetThingamajig(tl))) .Where(p => p.Value is null) .Select(p => p.Key)); 

That should do the trick ... and if you need to, you can still examine the exception that was thrown. And if you want to make it more beautiful, create a custom structure instead of KeyValuePair , which has more suitable property names, but the concept will remain the same.

+1
source

I suspect not. Any method may ultimately throw an exception.

0
source

All Articles