Anonymous static method differs between 2013 and 2015 debug builds

I hope someone can identify the language function (or error) that led to a change in the behavior of the program below. It is reproduced from a much larger script that is designed to register a message if the delegate provided in 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); } } } 

Scenario:

  • If I compile and run the debug construct created using Visual Studio 2013, the output is True .
  • If I compile and run the debug construct created using Visual Studio 2015, the output is False .
  • In both cases, the target .NET Framework is 4.5.
  • If I compile and run the release construct released using Visual Studio 2015, the output is True (and therefore corresponds to Visual Studio 2013).
  • Visual Studio 2015 is an RC version (if that matters).

I see from ildasm the generated 2013 code ...

 ___[MOD] C:\Sample.exe | MANIFEST |___[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() | | | 

... clearly different from the code generated in 2015 ...

 ___[MOD] C:\Sample.exe | MANIFEST |___[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 is not enough to determine if this is a new function or an unintentional error. I can get full IL dumps on request, but can someone tell me from the information I provided what is happening here and is this intentional? Why is the anonymous method considered static in 2013 but non-static in 2015?

+7
c #
source share
2 answers

I registered this problem as a Microsoft Connect ticket here and got a link to the C # specification, which confirmed that you cannot rely on any particular implementation for the closing type of the anonymous method. In particular,

6.5.1 / 2 "The list of calls of a delegate created from an anonymous function contains one entry. The exact target and target are not specified for the delegate method. In particular, it does not indicate whether the target of the delegate is zero, this is the value of the incoming member of the function, or another object. "

The Microsoft Connect ticket is also related to a similar issue here if anyone is interested. So in my case, in particular, it seems that the compiler is "working as intended", and the solution to my problem is "not to do this."

+1
source share

Obviously, the compiler can decide to generate this specific code both as an instance and as a static method. You should not rely on an optimization strategy.

0
source share

All Articles