Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to make an extension method work on a delegate

Consider the example below. I am able to make a call to an extension method for a delegate if first I define a variable of that delegate type. But I cannot call that extension method on a delegate which is passed as an argument. I don't get why it works the first time but doesn't work the second. What am I doing wrong?

public static class Extender
{
    public static Func<String, String> Compose(this Func<String, String> outer, Func<String, String> inner)
    {
        return input => outer(inner(input));
    }
}
public class Demo
{
    public void WillingToTakeStringToStringDelegate(Func<String, String> map)
    {
        // blah
    }
    public void RunMe()
    {
        Func<String, String> outer = x => "(outer: " + x + ")";

        // this works:
        var composition = outer.Compose(x => "(inner: " + x + ")");
        Trace.Write(composition("!"));  // ---> (outer: (inner: !))

        // this doesn't work:
        this.WillingToTakeStringToStringDelegate(
            (x => "(outer: " + x + ")").Compose(y => "(inner: " + y + ")")
        );
    }
}

UPDATE

for @philologon

As long as you don't mind having to assign your lambdas to variables then yes, you can use this method for creating partial applications of functions (currying) like a boss:

public static class CurryingHelper
{
    public static Func<X> Apply<A, X>(this Func<A, X> fun, A a)
    {
        return () => fun(a);
    }
    public static Func<B, X> Apply<A, B, X>(this Func<A, B, X> fun, A a)
    {
        return b => fun(a, b);
    }
    public static Func<B, C, X> Apply<A, B, C, X>(this Func<A, B, C, X> fun, A a)
    {
        return (b, c) => fun(a, b, c);
    }
    public static Func<B, C, D, X> Apply<A, B, C, D, X>(this Func<A, B, C, D, X> fun, A a)
    {
        return (b, c, d) => fun(a, b, c, d);
    }

    // etc... 
}

public class Demo
{
    public void RunMe()
    {
        Func<Int32, Int32, Int32, Int32> func = (a, b, c) => a - b + c;
        var funcA1 = func.Apply(1);
        Trace.Write(funcA1(2, 3));               // --> 2
        Trace.Write(funcA1.Apply(2).Apply(3)()); // --> 2
    }
}
like image 401
Trident D'Gao Avatar asked Oct 22 '13 18:10

Trident D'Gao


People also ask

What parameter does an extend () method requires?

Parameters of extend() function in Python The list extend() method has only one parameter, and that is an iterable. The iterable can be a list, tuple (it is like an immutable list), string, set or, even a dictionary.

Do extension methods have access to private members?

Extension methods can also access private static members of their static utility class. Even though this is tagged as C#, this applies to any of the . NET languages which provide support for extension methods.

Can we override extension method in C#?

You can use extension methods to extend a class or interface, but not to override them. An extension method with the same name and signature as an interface or class method will never be called.

Can we override extension method?

Extension methods cannot be overridden the way classes and instance methods are. They are overridden by a slight trick in how the compiler selects which extension method to use by using "closeness" of the method to the caller via namespaces.


1 Answers

There is nothing wrong with the conception, only some technical problems with the execution.

The point is that x => "(outer: " + x + ")" is not a delegate without context: it is a lambda expression that could either correspond to a delegate (of some type) or even to an expression tree. Therefore the type has to be explicitly or implicitly declared, e.g.

// this works:
this.WillingToTakeStringToStringDelegate(
    ((Func<string, string>)(x => "(outer: " + x + ")")).Compose(...)
);

This is the exact same reason why you cannot assign lambda functions to implicitly typed variables, e.g.

var f1 = (string s) => "Hello " + s;                   // does not work
Func<string, string> f2 = (string s) => "Hello " + s;  // works fine
like image 97
Jon Avatar answered Oct 14 '22 03:10

Jon