20

As a relative newbie I try to read as much as I can about a particular subject and test/write as much code as I can. I was looking at one of Jons Brainteasers (question #2) and my output was different than the answer. Which makes brings me here to ask if something has changed in recent versions and to see what output others are getting from this code.

The question is, "What will be displayed, why, and how confident are you?"

using System;

class Foo
{
    static Foo()
    {
        Console.WriteLine ("Foo");
    }
}

class Bar
{
    static int i = Init();

    static int Init()
    {
        Console.WriteLine("Bar");
        return 0;
    }
}

class Test
{
    static void Main()
    {
        Foo f = new Foo();
        Bar b = new Bar();
    }
}

What, if anything, would cause us to get two different answers?

Johannes Pille
  • 4,073
  • 4
  • 26
  • 27
Leroy Jenkins
  • 2,680
  • 6
  • 25
  • 33
  • 1
    You're asking "if something has changed in recent versions of Visual Studio". What you're really asking would be if anything changed in the newer version of the .NET Framework. And, really nothing that major would change from version to version, since it would be a Major Breaking Change. – Chris Pietschmann Oct 29 '09 at 17:17
  • 1
    Duplicated. Interesting. – Marc Gravell Oct 29 '09 at 17:19
  • 3
    Well, what's the answer you're getting? – Ryan Lundy Oct 29 '09 at 17:20
  • I was just reading about this on Jon's site earlier today. @jprete has it right, it's because of the static constructor in the Foo class. http://www.yoda.arachsys.com/csharp/beforefieldinit.html – ThatBlairGuy Jun 25 '10 at 16:07

5 Answers5

25

Now try it in release mode, outside of the debugger ;-p

I get different results with/without a debugger. The debugger upsets a lot of subtle nuances / optimisations, so I can only guess this is one of those times where the debugger matters. Which makes it even harder to debug ;-p

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
6

Jon's own answers page discusses this. I'm not a C# guy, but it seems like the system has exactly one choice of when to call the static foo code (and therefore write "Foo") but it has essentially infinite freedom to decide when to initialize Bar.i (which will write "Bar"), so it can happen either when the class is loaded, or when it is first used, or not at all.

jprete
  • 3,769
  • 21
  • 24
4

It prints Foo, Bar in Debug mode and Bar, Foo in Release mode. So what is happening is the Release code is optimized and the optimization causes Bar to be called first - but there is no guarantee that will always be the case.

Otávio Décio
  • 73,752
  • 17
  • 161
  • 228
  • 1
    Why does the optimization cause bar to be called first. What is the rule here? – Wil P Oct 29 '09 at 17:30
  • I would have to check, but I wouldn't be surprised if it is the debugger, more than debug/release, upsetting things. It regularly does. – Marc Gravell Oct 29 '09 at 17:32
  • 2
    Since bar doesn't have a static constructor, it can initialize the value for i and get the Bar class ready ahead of time. This prevents more work from happening later on. Alternatively, the debugger is letting Bar get initalized later. Foo, because it has the constructor, will always get initialized when first created, while Bar is free to be initialized anytime. – Will Eddins Oct 29 '09 at 17:33
  • @Marc - I ran both outside the IDE to get these results so I don't think the debugger is the factor here. – Otávio Décio Oct 29 '09 at 17:34
0

Just looking at it, I'd be surprised if it displayed anything else but "FooBar".

For the simple reason you are accessing Foo first, so its static constructor will run. Followed by the static field initializer when instantiating Bar.

Happy to be corrected.

Wim
  • 11,998
  • 1
  • 34
  • 57
0

I think that foo bar will be printed. The static type constructor would be executed first in Foo, then the Init method would be called on the Bar class. I don't know about whether or not the behavior could change though. This is interesting.

Wil P
  • 3,341
  • 1
  • 20
  • 20