In C# it is possible to create higher order functions, ie. functions g taking functions as arguments. Say I want to create such a function which given a function f and returns another function extending its functionality. How do I define argument names for the returned enhanced method? The motivation being, that I'm working with higher order methods in general, some of which produce new methods.. and these can be difficult to use as there is no parameter names etc. attached to them.
An example illustrating how g and f respectively could be defined in C#:
I define a method Extend that can extens methods taking a T as argument and returning an S.
static class M
{
public static Func< T, S> Extend(Func< T, S> functionToWrap)
{
return (someT) =>
{
...
var result = functionToWrap(someT);
...
return result;
};
}
}
We can then extend a method on our class without changing the method.
class Calc2
{
public Func< int, int> Calc;
public Calc2()
{
Calc = M.Extend< int, int>(CalcPriv);
}
private int CalcPriv(int positiveNumber)
{
if(positiveNumber < 0) throw new Exception(...);
Console.WriteLine("calc " + i);
return i++;
}
}
Alas, the argument name positiveNumber is no longer available, since the only available information is Func<int, int> Calc. That is when I use the extended method by typing new Calc2().Calc(-1) I get no help from the IDE that in fact my argument is wrong.
It would be nice if we could define a delegate and cast it to this, however, this is not possible.
Any suggestions?
If you only want a fixed delegate type with named parameters then you can just define your own delegate type:
Func is just defined like this:
public delegate TResult Func<in T, out TResult>(T arg)
So you can define your own delegate type with the parametername you want.
But in your example you want to preserve the delegate type passed in, so this doesn't work here. In theory you could define your function like this:
public static T Extend(T functionToWrap)
{
}
Unfortunately there are no good generic constraints which restrict the input type to a delegate with the right signature(Or even just delegates at all). But without these constraints the implementation would become so ugly, and you'd lose so much static type safety that IMO it's not worth it.
One workaround is using:
new MyFunc(Extend(f))
where MyFunc defines the parameternames you want.
Or you could do the following:
public static T ConvertDelegate<T>(Delegate d)
{
if (!(typeof(T).IsSubclassOf(typeof(Delegate))))
throw new ArgumentException("T is no Delegate");
if (d == null)
throw new ArgumentNullException();
MulticastDelegate md = d as MulticastDelegate;
Delegate[] invList = null;
int invCount = 1;
if (md != null)
invList = md.GetInvocationList();
if (invList != null)
invCount = invList.Length;
if (invCount == 1)
{
return (T)(object)Delegate.CreateDelegate(typeof(T), d.Target, d.Method);
}
else
{
for (int i = 0; i < invList.Length; i++)
{
invList[i] = (Delegate)(object)ConvertDelegate<T>(invList[i]);
}
return (T)(object)MulticastDelegate.Combine(invList);
}
}
public static TDelegate Extend<TDelegate,TArg,TResult>(Func<TArg,TResult> functionToWrap)
where TDelegate:class
{
Func<TArg,TResult> wrappedFunc= DoTheWrapping(functionToWrap);
return ConvertDelegate<TDelegate>(wrappedFunc);
}
BTW the ConvertDelegate function can be used to get Co/Contravariance on Delegates even prior to .net 4.
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