Extension Method for Function

I can create extension methods from any type. Once such a type is Func from int, for example.

I want to write extension methods for functions, not the type of return functions.

I can do it in a hacky way:

Func<int> getUserId = () => GetUserId("Email"); int userId = getUserId.Retry(2); 

If the Retry function is an extension method defined as:

 public static T Retry<T>(this Func<T> func, int maxAttempts) { for (int i = 0; i < maxAttempts; i++) { try { return func(); } catch { } } throw new Exception("Retries failed."); } 

What I really want to do:

 var userId = (() => GetUserId("Email")).Retry(2); 

But the compiler does not combine this function as Func of T.

I know about statics, including in Roslyn, so I could do something like:

 Retry(() => GetUserId("Email"), 2); 

But itโ€™s harder for me to read. I really want the helper function that I created to be out of the way.

There are other patterns that would give me similar results, such as monodic expressions or using a chain (i.e. converting T to a type of chain that has T inside, and then I write extension methods for Chain T), The problem I'm having I come across this approach, is that you need to start with an expression by clicking on a chain from T, and then end the expression by clicking on T, which is a lot of noise distracting the reader's attention from my business logic.

I know I can use implicit casting in a chain from T to T, but it looks like he is doing magic behind the scenes.

So is it possible to get a link to a function without first executing it, with a small amount of boiler plate code?

End of the day, I would like to write the following for any kind of Func / Action:

 var settings = LoadSettingsFromDatabase().Retry(2); 
+7
c #
source share
3 answers

Per this question , I think the answer is no.

I would advise you to go with the static inclusion of Retry , as you suggested:

 Retry(() => GetUserId("Email"), 2); 

It makes the intention clear, uncomplicated, readable enough, and this is idiomatic C #.

An idea that I don't like:

If you want to change the arguments of a method, the following will work (but I think most people find this pretty horrible):

 public static T AttemptsAt<T>(this int maxAttempts, Func<T> func) { for (int i = 0; i < maxAttempts; i++) { try { return func(); } catch { } } throw new Exception("Retries failed."); } 

Using:

 var userId = 2.AttemptsAt(() => GetUserId("Email")); 
+6
source share

Of course, if you need one liner, you will need to explicitly specify the desired delegate type:

 var userId = ((Func<int>)(() => GetUserId("Email"))).Retry(2); 
+1
source share

I donโ€™t know if it answers your question, but it seems possible to define a func (or action) extension method, see

http://www.codeproject.com/Articles/1104555/The-Function-Decorator-Pattern-Reanimation-of-Func . To quote mr Jordan:

 public static Func<TArg, TResult> RetryIfFailed<TArg, TResult> (this Func<TArg, TResult> func, int maxRetry) { return (arg) => { int t = 0; do { try { return func(arg); } catch (Exception) { if (++t > maxRetry) { throw; } } } while (true); }; } .... // get the method we are going to retry with Func<DateTime, string> getMyDate = client.GetMyDate; // intercept it with RetryIfFailed interceptor, which retries once at most getMyDate = getMyDate.RetryIfFailed(1); for (var i = 0; i < TimesToInvoke; i++) { try { // call the intercepted method instead of client.GetMyDate getMyDate(DateTime.Today.AddDays(i % 30)); counter.TotalSuccess++; } catch (Exception ex) {counter.TotalError++; } .... 
0
source share

All Articles