views:

344

answers:

3

I'm trying to figure out a way to automatically cast something to an Action or Func and the best I can come up with is something like this:

[TestFixture]
public class ExecutionTest
{
    public void BadMethod()
    {
        throw new Exception("Something bad happened");
    }

    [Test]
    public void TestBadMethod()
    {
        // Want this, but it won't work!!
        // BadMethod.Execute().IgnoreExceptions();

        // Ick
        ((Action)BadMethod).Exec().IgnoreExceptions();

        // Still ick
        ((Action)BadMethod).IgnoreExceptions();

        // Do not want
        ExtensionMethods.Exec(BadMethod).IgnoreExceptions();

        // Better but still meh
        this.Exec(BadMethod).IgnoreExceptions();

    }
}

public static class ExtensionMethods
{
    public static Action Exec(this Action action)
    { return action; }

    public static Action Exec(this object obj, Action action)
    { return action; }

    public static void IgnoreExceptions(this Action action)
    {
        try { action(); }
        catch {}
    }
}

There has to a better/easier way to do this, any thoughts?

+2  A: 

In C#, when you use the method name without parenthesis, it's called a method group and it has no representation other than at compile time. A method group can represent more than one method (because of overloads and overrides), therefore to implictly identify which method is needed, a target delegate type must be provided.

In your case, you are wondering why the extension method parameter type won't trigger the resolution of the function. Simply put, extension are evaluated after the type is known, that is, the this parameter can't be used as an implicit conversion target.

Example of why it would break:

class Test
{
    void M (void) // Fits Action delegate
    {
    }

    int M (int) // Fits Funct<int,int> delegate
    {
        return 5;
    }

    void Test()
    {
        M.Exec(); // UHOH!!! Which Exec to resolve to ???
    }
}


public static class Extensions
{
    public static void Exec(this Action action) { }
    public static void Exec(this Func<int, int> func) { }
}

As you can see, there is a conflict, but as a matter of fact, the conflict never happens because C# won't even try to find a matching extension with a method group.

Note how this won't work neiter:

class A
{
    public static implicit operator int (A a)
    {
        return 5;
    }

    void F()
    {
       A a = new A();
       a.Blah(); // Error! It won't implicitly try C.Blah()
    }
}

public static class C
{
    public static void Blah (int i)
    {
    }
}

C# won't match A to C.Blah(int) because it would require an implicit conversion.

Coincoin
Not sure that it is an issue of method overloads because the compiler will figure out which one to call. But this is the best answer that I've seen so far...
JeremyB
A: 

As Coincoin says, it's not gonna work well in C# because of the overzealous love for method overloading. The only workaround I've seen people use is to create Action and Func methods:

public Action Action(Action f) { return f; }
public Action<A> Action<A>(Action<A> f) { return f; }
...
public Func<A,B,C,D,E> Func(Func<A,B,C,D,E> f) { return f; }

You could even call them all "F" to get some sort of short syntax:

F(BadMethod).NoExceptions();

You might decide to not define these methods in your class, and put them in a Funcs utility or something. Alias it with F and it doesn't end up too bad:

F.F(BadMethod).NoException();

But overall it still sucks :(.

MichaelGG
Yeah, that is why I had the extension method for (this Object object, Action action) so it would work inside any class by calling this.Action() or this.Func()
JeremyB
Sorry, I didn't see the Exec definition -- somewhat misleading name, no :P
MichaelGG
Yeah, I renamed it in my actual code. It seemed "fluent" at the time.
JeremyB
A: 

F# lets you do this kind of thing very naturally by providing a much better type inference system.

Mo Flanagan