Reputation: 59151
I would like to write an extension method for a generic type, with additional generic type parameters. I have working code already, but don't like the result, because the user is required to re-enter the generic type parameters of the existing type.
I have a concrete example, but keep in mind that this is a general problem. I appreciate feedback on the particular problem at hand, but I am looking for general solutions.
For a class of type Action<T>
, add an extension method with a signature similar to this:
Func<T, TResult> ToFunc<TResult>();
Here's my working code:
public static class DelegateExtensions
{
public static Func<T, TResult> ToFunc<T, TResult>(this Action<T> action)
{
return arg => { action(arg); return default(TResult); };
}
}
But the usage stinks:
public void TakesAFunc(Func<int, float> someFunc) { /* ... */ }
// ...
Action<int> someIntAction = /* ... */;
TakesAFunc(someIntAction.ToFunc<int, float>());
In this example, the int
generic parameter is the only value that is acceptable, so it causes unnecessary code duplication.
Type inference does not work here. I think this is because you can't infer a generic parameter via return type.
This code would solve the problem, but unfortunately does not seem to work:
public static class DelegateExtensions<T>
{
public static Func<T, TResult> ToFunc<TResult>(this Action<T> action)
{
return arg => { action(arg); return default(TResult); };
}
}
Usage would be exactly like you'd expect:
public void TakesAFunc(Func<int, float> someFunc) { /* ... */ }
// ...
Action<int> someIntAction = /* ... */;
TakesAFunc(someIntAction.ToFunc<float>());
I noticed that System.Linq.Queryable
works the way my first chunk of code does, though it usually doesn't need extra type parameters, so type inference works.
Is there any known trick to get around requiring these duplicate generic type parameters? One thought that comes to mind would be code generators or macros of some sort, but I can't think of how I'd do it cleanly.
Upvotes: 4
Views: 596
Reputation: 1633
I am late to the party - sorry.
As has been mentioned - this is not currently possible with out switching the Func to an out param.
I'll throw out another way to do this sort of thing - it gets to look a bit fluid syntax like, but it works.
public class ActionWrap<T>
{
private readonly Action<T> _action;
internal ActionWrap(Action<T> action)
{
_action = action;
}
public Func<T, TResult> OfType<TResult>()
{
return arg => { _action(arg); return default(TResult); };
}
}
public static class DelegateExtensions
{
public static ActionWrap<T> ToFunc<T>(this Action<T> action)
{
return new ActionWrap<T>(action);
}
}
Then calling it goes:
Action<int> x = z=> Console.WriteLine(z);
Func<int, float> asFunc = x.ToFunc().OfType<float>();
This is not exactly what you wanted, but it achieves the goal of not stating the int generic again and can be extended to other cases where you want to do something similar.
Upvotes: 2
Reputation: 6155
One common trick for this sort of thing is to pass a dummy value of the desired type just for type inference, which is required in certain scenarios involving anonymous types.
public static class DelegateExtensions
{
public static Func<T, TResult>
ToFunc<T, TResult>(this Action<T> action, TResult ignored)
{
return arg => { action(arg); return default(TResult); };
}
}
How good of a trick this is is up to personal opinion, but this would confuse me every time I called it and every time I came back to a place that I called it. You could also change the semantics of the method to make the second parameter be the return value, allowing the caller to decide if they want the default value or not.
As to your second example, I'm pretty sure extension methods are not allowed on generic types, but I don't have a link handy
Upvotes: 3