为什么我不能使用Extension方法隐式地转换Delegate?

时间:2021-02-14 21:04:23

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:

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

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

有没有更好/更简单的方法来做这个,任何想法?

3 个解决方案

#1


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.

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

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.

正如您所看到的,存在冲突,但事实上,冲突永远不会发生,因为C#甚至不会尝试使用方法组来查找匹配的扩展。

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.

C#将不匹配A到C.Blah(int),因为它需要隐式转换。

#2


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:

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

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

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

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:

您可能决定不在类中定义这些方法,并将它们放在Funcs实用程序中。用F替代它并且它不会太糟糕:

F.F(BadMethod).NoException();

But overall it still sucks :(.

但整体而言仍然很糟糕:(。

#3


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

F#允许您通过提供更好的类型推理系统来自然地完成此类操作。

#1


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.

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

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.

正如您所看到的,存在冲突,但事实上,冲突永远不会发生,因为C#甚至不会尝试使用方法组来查找匹配的扩展。

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.

C#将不匹配A到C.Blah(int),因为它需要隐式转换。

#2


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:

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

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

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

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:

您可能决定不在类中定义这些方法,并将它们放在Funcs实用程序中。用F替代它并且它不会太糟糕:

F.F(BadMethod).NoException();

But overall it still sucks :(.

但整体而言仍然很糟糕:(。

#3


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

F#允许您通过提供更好的类型推理系统来自然地完成此类操作。