Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Anonymous method staticness different between 2013 and 2015 debug compilations

Tags:

c#

I'm hoping someone can identify the language feature (or bug) that resulted in the change in behaviour of the program below. It is reproduced from a much larger scenario that was intended to log a message if the delegate supplied to Orchard::Go was not static.

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);
        }
    }
}

The scenario is:

  • If I compile and run a debug build produced with Visual Studio 2013, the output is True.
  • If I compile and run a debug build produced with Visual Studio 2015, the output is False.
  • In both cases, the target .NET Framework is 4.5.
  • If I compile and run a release build produced with Visual Studio 2015, the output is True (and thus consistent with Visual Studio 2013).
  • Visual Studio 2015 is the RC version (if that matters).

I can see from ildasm the 2013 generated code...


    ___[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()
       |   |
       |

...is clearly different to the 2015 generated code...


    ___[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()
       |   |
       |

...but my knowledge of IL and compiler changes isn't sufficient to determine whether this is a new feature or an unintended bug. I can produce the full IL dumps on request, but can anyone tell me from the information I've supplied what is going on here and whether it is intentional? Why is the anonymous method considered static in 2013 but non-static in 2015?

like image 254
ScheuNZ Avatar asked Jun 18 '15 04:06

ScheuNZ


1 Answers

I logged this problem as a Microsoft Connect ticket here and was provided with a reference to the C# specification that confirmed you can't rely on any specific implementation for the enclosing type of an anonymous method. Specifically,

6.5.1/2 "The invocation list of a delegate produced from an anonymous function contains a single entry. The exact target object and target method of the delegate are unspecified. In particular, it is unspecified whether the target object of the delegate is null, the this value of the enclosing function member, or some other object."

The Microsoft Connect ticket also linked to a similar issue here if anyone is interested. So in my case specifically it appears the compiler is "Working as intended" and the solution to my problem is to "not do that".

like image 92
ScheuNZ Avatar answered Oct 20 '22 00:10

ScheuNZ