【问题标题】:Working with methods that return anonymous methods使用返回匿名方法的方法
【发布时间】:2014-06-22 07:40:11
【问题描述】:

如果我有这样的课程:

public class SomeClass
{
    public Action<string> SomeAction { get; set; }

    public SomeClass()
    {
        SomeAction = GetSomeAnonymousMethod();
    }

    private Action<string> GetSomeAnonymousMethod()
    {
        return (text) =>
        {
            Console.WriteLine(text);
        };
    }
}

当我创建SomeClass 的新实例时会发生什么?我的印象是构造函数只是调用GetSomeAnonymousMethod(),它返回一个新的委托实例(它只包含对匿名方法的编译器生成的支持方法的引用),并将其分配给@ 987654324@财产。

有人可以证实,还是发生了更险恶的事情?

【问题讨论】:

    标签: c# lambda anonymous-methods


    【解决方案1】:

    嗯,这就是几乎所有发生的事情。在这种特殊情况下,您的 lambda 表达式(它不是匿名方法,很挑剔)不需要任何状态,因此生成的方法可以是静态的,并且可以缓存委托引用。所以“新委托实例”部分可能是正确的。

    所以它更多是这样的 - 至少在使用 MS 编译器编译时:

    public class SomeClass
    {
        private static Action<string> cachedAction;
        public Action<string> SomeAction { get; set; }
    
        public SomeClass()
        {
            SomeAction = GetSomeAnonymousMethod();
        }
    
        private Action<string> GetSomeAnonymousMethod()
        {
            Action<string> action = cachedAction;
            if (action == null)
            {
                action = AnonymousMethodImplementation;
                cachedAction = action;
            }
            return action;
        }
    
        private static void AnonymousMethodImplementation(string text)
        {
            Console.WriteLine(text);
        }
    }
    

    您无需担心其中的细节 - 这都是一个实现细节......只是一点点优化。但如果你真的想知道发生了什么,那就更接近现实了。

    与以往一样,要查看编译器所做工作的详细信息,您可以随时使用 ildasm(或 IL 模式下的 Reflector)并查看生成的 IL。

    【讨论】:

    • 有太多人担心这些细节,而不是用他们的头脑来获得整个编程语言的更高技能。我相信这样的低级细节不应该成为开发人员关心的问题。如果语言规范说“这样做”,这应该是一个问题:它如何在语言级别工作......
    • @MatíasFidemraizer:在 99.9% 的情况下,这是正确的 - 但我不想阻止任何人调查它是如何实施的。
    • 不,不。我同意你。我在这里提出了我对通用主题本身的看法,但我并没有阻止任何人获得如此有价值的信息! :)
    • 哦,我只是想看看我是否不小心在没有意识到的情况下制作了大量对象,但我很高兴 C# 足够聪明,能够实现我的意图。
    • @KyleBaran C# 是上帝:D
    【解决方案2】:

    有人可以证实,还是发生了更险恶的事情?

    这似乎是新冷战和第二次冷战事件中的另一个秘密行动!

    是的,您的构造函数正在执行您在问题中描述的内容。

    我会解释匿名代表使用delegate type inference转换为Action&lt;string&gt;

    例如以下代码行:

    return (text) =>
            {
                Console.WriteLine(text);
            };
    

    ...推断为:

    return new Action<string>((text) => 
    {
         Console.WriteLine(text);
    });
    

    【讨论】:

    • 我希望您的“翻译”不正确,因为它不维护(外部可见的)缓存行为 - 但它确实如此!这是一个有趣的案例,其中new 实际上并不意味着new...
    • @JonSkeet externally visible 缓存行为是什么意思?
    • 我的意思是你可以object.ReferenceEquals(new SomeClass().SomeAction, new SomeClass().SomeAction)返回true,如果为每个类实例生成一个新的委托就不会出现这种情况。
    • @JonSkeet 我明白了。但是,如果我在您的答案中检查您自己的示例,您将展示 CSC 如何在幕后生成匿名委托方法。归根结底,不管有没有委托类型推断,它都应该编译相同的 IL。无论是新的还是非新的,区别应该是委托类型推断语法糖的工作方式。我的意思是,结果是预期的结果,不是吗?
    • 这不是我所期望的,不。我希望每次使用new 时,我都会得到一个真正的新实例。否则,这个词肯定会失去意义。这不仅仅是类型推断 - 它不像您只是将 lambda 表达式强制转换Action&lt;string&gt;。您正在使用委托实例创建表达式,我希望它会创建一个新实例。这没什么大不了的,但让我感到惊讶。
    猜你喜欢
    • 2016-02-19
    • 2019-09-05
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    • 2011-08-27
    • 2020-03-14
    • 1970-01-01
    相关资源
    最近更新 更多