2013和2015调试编译之间的匿名方法静态不同

Sch*_*uNZ 7 c#

我希望有人可以识别出导致下面程序行为发生变化的语言特性(或bug).如果提供给Orchard :: Go的委托不是静态的,则会从更大的场景中重现它,该场景旨在记录消息.

using System;

namespace Sample
{
    public static class Program
    {
        public static void Main()
        {
            new Apple();
        }
    }

    public sealed class Apple
    {
        public Apple()
        {
            Orchard.Go(() => { });
        }
    }

    internal static class Orchard
    {
        public static void Go(Action action)
        {
            Console.WriteLine(action.Method.IsStatic);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

场景是:

  • 如果我编译并运行使用Visual Studio 2013生成的调试版本,则输出为True.
  • 如果我编译并运行使用Visual Studio 2015生成的调试版本,则输出为False.
  • 在这两种情况下,目标.NET Framework都是4.5.
  • 如果我编译并运行使用Visual Studio 2015生成的发布版本,则输出为True(因此与Visual Studio 2013一致).
  • Visual Studio 2015是RC版本(如果重要的话).

我可以从ildasm看到2013年生成的代码......


    ___[MOD] C:\Sample.exe
       |      M A N I F E S T
       |___[NSP] Sample
       |   |___[CLS] Sample.Apple
       |   |   |     .class public auto ansi sealed beforefieldinit 
       |   |   |___[STF] CS$9__CachedAnonymousMethodDelegate1 : private static class [mscorlib]System.Action
       |   |   |___[MET] .ctor : void()
       |   |   |     b__0 : void()
       |   |
       |   |___[CLS] Sample.Orchard
       |   |   |     .class private abstract auto ansi sealed beforefieldinit 
       |   |   |___[STM] Go : void(class [mscorlib]System.Action)
       |   |
       |   |___[CLS] Sample.Program
       |   |   |     .class public abstract auto ansi sealed beforefieldinit 
       |   |   |___[STM] Main : void()
       |   |
       |
Run Code Online (Sandbox Code Playgroud)

......明显不同于2015年生成的代码......


    ___[MOD] C:\Sample.exe
       |      M A N I F E S T
       |___[NSP] Sample
       |   |___[CLS] Sample.Apple
       |   |   |     .class public auto ansi sealed beforefieldinit 
       |   |   |___[CLS] c
       |   |   |   |     .class nested private auto ansi serializable sealed beforefieldinit 
       |   |   |   |     .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )  ...
       |   |   |   |___[STF] 9 : public static initonly class Sample.Apple/'c'
       |   |   |   |___[STF] 9__0_0 : public static class [mscorlib]System.Action
       |   |   |   |___[STM] .cctor : void()
       |   |   |   |___[MET] .ctor : void()
       |   |   |   |     b__0_0 : void()
       |   |   |
       |   |   |___[MET] .ctor : void()
       |   |
       |   |___[CLS] Sample.Orchard
       |   |   |     .class private abstract auto ansi sealed beforefieldinit 
       |   |   |___[STM] Go : void(class [mscorlib]System.Action)
       |   |
       |   |___[CLS] Sample.Program
       |   |   |     .class public abstract auto ansi sealed beforefieldinit 
       |   |   |___[STM] Main : void()
       |   |
       |
Run Code Online (Sandbox Code Playgroud)

...但我对IL和编译器更改的了解不足以确定这是一个新功能还是一个意外的错误.我可以根据要求生成完整的IL转储,但任何人都可以告诉我我提供的信息在这里发生了什么,是否是故意的?为什么匿名方法在2013年被认为是静态的,而在2015年是非静态的?

Sch*_*uNZ 1

我在此处将此问题记录为 Microsoft Connect 票证,并提供了对 C# 规范的引用,该规范确认您不能依赖匿名方法的封闭类型的任何特定实现。具体来说,

6.5.1/2 “由匿名函数生成的委托的调用列表包含单个条目。委托的确切目标对象和目标方法未指定。特别是,未指定委托的目标对象是否为 null 、封闭函数成员的 this 值或其他某个对象。”

如果有人感兴趣的话,Microsoft Connect 票证还链接到类似的问题。因此,就我而言,具体而言,编译器似乎“按预期工作”,而我的问题的解决方案是“不这样做”。