为什么方法在语法上不能像func / action委托一样工作?

时间:2016-09-14 22:18:40

标签: c#

在回家的路上,我有了一个想法:创建Func / Action扩展,这将允许c#中的一些很好的语法糖。

理论示例...为Func / Action的各种排列创建一个扩展,允许您为方法的执行计时。

当我到家并尝试一个例子时,我发现这不可能。我认为这是c#的缺点/不一致。代表和方法是相同的(在理论上)。

public static class Extensions
{
    public static void Time(this Action action)
    {
        // Logic to time the action
        action();
    }
}

public class Example
{
    public void Main()
    {
        Action action = RunApp;
        Action actionLambda = () => { };
        Action actionDelegate = delegate () { };

        Extensions.Time(RunApp); // Works
        Extensions.Time(() => { }); // Works
        Extensions.Time(delegate() { }); // Works
        Extensions.Time(action); // Works
        Extensions.Time(actionLambda); // Works
        Extensions.Time(actionDelegate); // Works

        action.Time(); // Works
        actionLambda.Time(); // Works
        actionDelegate.Time(); // Works

        ((Action) RunApp).Time(); // Works
        ((Action) delegate () { }).Time(); // Works
        ((Action) (() => { })).Time(); // Works

        // These should all be the same! 

        RunApp.Time(); // No good: "Example.RunApp() is a method which is not valid in the given context"
        () => { }.Time(); // No good: Operator '.' cannot be applied  to operand of type 'lambda expression'"
        (() => { }).Time(); // No good: Operator '.' cannot be applied  to operand of type 'lambda expression'"
        delegate() { }.Time(); // No good: "Operator '.' cannot be applied operand of the type 'anonymous method'"
    }

    public void RunApp()
    {
        // Stuff...
    }
}

我理解Func / Action是c#与代理和方法组相比的新增内容,但为什么它们都不能同样行事呢?

1 个答案:

答案 0 :(得分:0)

Action很好地以简单的方式封装了委托,而无需显式声明您的委托。在C#中,delegate是将方法捕获为类型的语言机制。你需要一个类型来创建一个扩展方法....所以,简化回代表...

 public static class Extensions
    {
        public delegate void Del();
        public static void Time(this Del action)
        {
            // Logic to time the action
            action();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {            
            ((Extensions.Del)(() => { })).Time();
        }
    }

语言不会自动将方法转换为Del,您需要明确这样做。方法本身不是类型,委托是捕获它们的机制。从根本上说,在c#中,委托与方法不同。这是C#的解决方案,有方法的类型安全指针。

要记住的另一件事是你能做到: -

 public static class Extensions
    {
        public delegate void Del();
        public delegate void Del2();
        public static void Time(this Del action)
        {
            // Logic to time the action
            action();
        }
        public static void Time(this Del2 action)
        {
           // Logic to time the action
           action();
        }


        public static void Time(this Action action)
        {
            // Logic to time the action
            action();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {            

            ((Extensions.Del)(() => { })).Time();
            ((Extensions.Del2)(() => { })).Time();
            ((Action)(() => { })).Time();

            (() => { })).Time();   // no way to know what type this should be coerced to

        }        
    }

现在您的方法可以被捕获为多种不同的类型。