I can create extension methods off any type. Once such type is Func of int for example.
I want to write extension methods for functions, not the return type of functions.
I can do it in a hacky way:
Func<int> getUserId = () => GetUserId("Email");
int userId = getUserId.Retry(2);
Where the function Retry 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 is:
var userId = (() => GetUserId("Email")).Retry(2);
But the compiler doesn't reconcile the function as a Func of T.
I know of the static including in Roslyn, so I could do something like:
Retry(() => GetUserId("Email"), 2);
But I find this harder to read. I really want the helper function I create to be out of the way.
There are other patterns out there that would give me similar results, such as monadic expressions, or using chaining (i.e. convert T to a chain type, that internally has a T, and then I write extension methods for Chain of T). The problem I have with this approach is you have to start off the expression by casting to a Chain of T, and then end the expression by casting to T, which is a lot of noise pulling the reader's attention away from my business logic.
I know I could use implicit casting on Chain of T to T, but this feels like it's doing some magic behind the scenes.
So is it possible to get the reference to a function, without executing it first, with little to no boiler plate code?
End of the day I'd Like to write the following for any kind of Func / Action:
var settings = LoadSettingsFromDatabase().Retry(2);
Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are static methods, but they're called as if they were instance methods on the extended type.
To define an extension method, first of all, define a static class. For example, we have created an IntExtensions class under the ExtensionMethods namespace in the following example. The IntExtensions class will contain all the extension methods applicable to int data type.
In C#, the extension method concept allows you to add new methods in the existing class or in the structure without modifying the source code of the original type and you do not require any kind of special permission from the original type and there is no need to re-compile the original type.
To define and call the extension methodDefine a static class to contain the extension method. The class must be visible to client code. For more information about accessibility rules, see Access Modifiers. Implement the extension method as a static method with at least the same visibility as the containing class.
Per this question, I think the answer is "no".
I would advise you go with a static include of Retry
, as you suggested:
Retry(() => GetUserId("Email"), 2);
It makes intent clear, it's uncomplicated, it's readable enough, and it's idiomatic C#.
An idea that I don't like:
If you were willing to reverse your method arguments, the following would work (but I think most people would think it's pretty awful):
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.");
}
Usage:
var userId = 2.AttemptsAt(() => GetUserId("Email"));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With