7

我正在尝试找出一种自动将某些内容投射到 Action 或 Func 的方法,而我能想到的最好的方法是这样的:

[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 {}
    }
}

必须有更好/更简单的方法来做到这一点,有什么想法吗?

4

3 回答 3

5

在 C# 中,当您使用不带括号的方法名称时,它被称为方法组,除了在编译时它没有任何表示。一个方法组可以表示多个方法(因为重载和覆盖),因此要隐式识别需要哪个方法,必须提供目标委托类型。

在您的情况下,您想知道为什么扩展方法参数类型不会触发函数的解析。简单来说,extension是在类型已知后才计算的,也就是说this参数不能作为隐式转换目标。

为什么会中断的示例:

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

    int M (int) // Fits Func<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) { }
}

如您所见,存在冲突,但事实上,冲突从未发生过,因为 C# 甚至不会尝试找到与方法组匹配的扩展。

请注意这也不起作用:

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# 将不匹配AC.Blah(int)因为它需要隐式转换。

于 2009-02-12T23:19:46.977 回答
3

正如 Coincoin 所说,由于对方法重载的过分热爱,它在 C# 中不会很好地工作。我见过人们使用的唯一解决方法是创建 Action 和 Func 方法:

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; }

您甚至可以将它们都称为“F”以获得某种简短的语法:

F(BadMethod).NoExceptions();

您可能决定不在您的类中定义这些方法,并将它们放在 Funcs 实用程序或其他东西中。用 F 给它起别名,结果不会太糟糕:

F.F(BadMethod).NoException();

但总的来说它仍然很烂:(。

于 2009-02-13T04:06:22.840 回答
1

F# 通过提供更好的类型推断系统,让您可以非常自然地做这种事情。

于 2010-01-08T18:19:05.603 回答