Functional C# - using or returning Action's
Browsing the net for better fault handling in C#, I've com across the following to implementation strategies. The first one is natural to me, while the other implementation I'm not certain what its advantages are?
1)
static void Fault(Action protectedBlock, Action faultHandler)
{
try
{
protectedBlock();
}
catch
{
faultHandler();
throw;
}
}
2)
static Action Fault(Action protectedBlock, Action faultHandler) { return () => { try { protectedBlock(); } catch { faultHandler(); throw; } }; }
Is 2) the preferred strategy when developing higher order functions in C#?
And, I am wondering, if one approach is more efficient开发者_JAVA技巧 than the other.
The second case is like a Faultable Action Factory. Where you pass in a delegate of what you want to do, protectedBlock
, and a delegate of what to do when an Exception
occurs, faultHandler
. The actions are returned wrapped in a try/catch structure as an aggregate Action
. My problem with both these methods is no Exception
is actually being caught so who ever is going to catch your throw has no information on which to act.
The difference in execution between the 2 is when they actually execute. The 1st will be executed when it's called. The 2nd will execute whenever the returned Action
is called. I don't think the efficiency difference would be significant.
(2) can be further composed, whilst (1) just runs. But neither are exactly "functional" as Action
is not a function (compare with Func<A, R>
).
So with (2) you could do:
Fault(someAction, Fault(firstTryFaultHandler, lastDitchFaultHandler))();
...and get expected behavior. That doesn't work with (1)
In C#, approach 2 can be confusing. A caller might use "Fault(a, b);" expecting a and possibly b to be called. Instead, a lambda is created, returned and discarded. In other words nothing is done.
Regarding efficiency, approach 2 is a bit wasteful if most of your calls are of the form "Fault(a,b)();", i.e. you invoke the lambda immediately. In this situation, you don't need a lambda.
For these reasons, I would prefer approach 1. If you need to defer execution, you can introduce a lambda explicitly "() => Fault(a, b)".
精彩评论