为什么我不能使用扩展方法隐式转换委托?

发布于 2024-07-13 12:51:41 字数 1038 浏览 11 评论 0原文

我正在尝试找出一种自动将某些内容转换为 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 {}
    }
}

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

书信已泛黄 2024-07-20 12:51:41

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

在您的情况下,您想知道为什么扩展方法参数类型不会触发函数的解析。 简单地说,扩展是在类型已知后才进行评估的,即 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) 匹配,因为它需要隐式转换。

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 implicitly 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 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) { }
}

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 either:

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.

许仙没带伞 2024-07-20 12:51:41

正如 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();

但总的来说,它仍然很糟糕:(。

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 :(.

雨后彩虹 2024-07-20 12:51:41

F# 通过提供更好的类型推断系统,让您可以非常自然地完成此类操作。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文