Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

It is possible to cast to a delegate with named parameters, by dynamically binding a newly constructed delegate to the underlying Func delegate method:

public delegate double CalcFunc(double value);

static class M
{
    public static Func<T, S> Extend<T,S>(Func<T, S> functionToWrap)
    {
      return (someT) => functionToWrap(someT);
    }
}

class Program
{
    private static double Calc(double input)
    {
        return 2*input;
    }

    [STAThread]
    static void Main()
    {
        Func<double, double> extended = M.Extend<double, double>(Calc);

        CalcFunc casted = (CalcFunc)Delegate.CreateDelegate(typeof(CalcFunc), extended.Target, extended.Method);
        Console.WriteLine(casted(2) + " == 4");
        Console.WriteLine("I didn't crash!");
        Console.ReadKey();
    }
}

One word of warning: this will not do any compile-time checking of the cast. If the signatures don't match exactly, you'll get a bind failure at runtime (excepting special support for contravariance in .NET 4).

That's the beauty of anonymous delegates; they're anonymous. A Func is a delegate to a method that takes an int and returns an int. What the function actually does, and therefore the names of the parameters, is irrelevant.

The only way this would work is if Calc were of a named delegate type, defined with a signature identical to CalcPriv. It would all still work as written, including the anonymous extension, but you'd have a named parameter for Calc.

Another way to impart the information would be to xml-doc Calc with a ///<summary></summary> tag describing the parameter Calc was designed to take.

Lastly, you could derive from Func<T,TResult> to create a TakesPositiveInteger<T,TResult> class. This is going a little far, but if you wanna talk about self-documenting code...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top