匿名函数vs方法组 - 委托给实例方法不能为null

时间:2018-01-19 23:41:49

标签: c# .net anonymous-function method-group

在尝试将匿名函数转换为方法组时,我偶然发现了一个奇怪的问题。下面的例子很好地说明了这个问题 - 有两种方法 - Run()和Crash(),除了使用匿名函数和方法组外,它们都做同样的事情。

基本上问题是我想创建一个Func来调用一个对象上的方法,该方法在应用程序启动时没有初始化,而是在此func运行之前。使用匿名函数效果很好,但转换为方法组会导致异常。

坚持使用匿名函数而不是方法组并不是什么大不了的事,但是出现了一个警告RCS1207,我想先了解这个问题的原因,然后再用内联注释禁用它。 / p>

namespace AnonymousFunctionVsmethodGroup
{
    class Program
    {
        static void Main(string[] args)
        {
            var app = new App();
            app.Run();
            app.Crash();
        }
    }

    public class App
    {
        private Func<string> m_Func;

        public void Run()
        {
            Entity cat = null;

            // Anonymous function. At this point cat is null
            m_Func = () => cat.GetName();

            // Initializing new cat
            cat = new Entity("Cat");

            // Func is executed on a valid cat
            Console.WriteLine(m_Func());
            Console.Read();
        }

        public void Crash()
        {
            Entity cat = null;

            // Method group. At this point cat is null. Code never gets through here and an exception is thrown instead.
            // "Delegate to an instance method cannot have null this"
            m_Func = cat.GetName;

            // Initializing new cat
            cat = new Entity("Cat");

            // Func is executed on a valid cat?
            Console.WriteLine(m_Func());
            Console.Read();
        }
    }

    // Sample entity
    public class Entity
    {
        private string name;

        public Entity(string name)
        {
            this.name = name;
        }

        public string GetName()
        {
            return name;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

()=&gt; GetName()是一个lambda或annoymous函数。编译器使用这种语法做了一些聪明的事情,并且实际上在你编写它的类上创建了另一个方法(这是一个非常简单的过程,但它现在会做,请查看闭包以获取更多信息)。 lambda中的代码被移动到这个新方法中,并且仅在您评估lambda时调用,即当您调用func时。而使用cat.GetName传入属于cat实例的方法,该方法为null,因此您无法在该点访问它

答案 1 :(得分:1)

当您指定&#34;方法组&#34;时,将立即调用与该对象关联的委托。但是,lambda会创建一个额外的重定向:代码将首先调用存储对可能不存在的对象上的方法的匿名引用,并获取零个,一个或多个参数,并使用该参数调用Facade.Entity.GetName。在您的情况下,它不会将任何参数传递给方法委托,但只要您不执行匿名方法,它就只代表类上方法调用的签名。

如果你看一下匿名方法的定义,&#34;它们是没有名字的方法。我们可以编写没有任何名称的小方法块,并将其地址分配给委托对象,然后使用此委托对象来调用它。&#34;