Why is there a difference in behaviour of an application built in VS 2010 v.s. VS 2012?

前端 未结 2 1783
梦如初夏
梦如初夏 2021-02-07 04:08

I was checking whether installing .NET 4.5 on our build machines changes the output IL image generated by VS 2010.

Since I know the behaviour of foreach has changed in .

相关标签:
2条回答
  • 2021-02-07 04:49

    Visual Studio uses an in-process compiler, so it knows which version of C# it's using.

    As you noted, csc.exe from the command line, on the other hand, uses whatever C# version it's made to compile, so in your case it'll be C# 5.0. Since it's an in-place upgrade (in terms of installation directory), it might break code that relied on the foreach binding being the same across the whole loop (odd, but possible).


    NOTE: Old answer for the wrong question: the OP knows this and was testing it from the command line.

    The blog post you link to already answers your question. I think this question is related to this one.

    It's the compiler that changed, so this:

    foreach (int value in values)
    {
        // ...
    }
    

    used to generate something along the following code:

    {
        int value;
        for (/* iteration */)
        {
            value = /* get from enumerator */;
            // ...
        }
    }
    

    while the new C# compiler now generates the equivalent of moving the variable to inside the loop:

    for (/* iteration */)
    {
        int value = /* get from enumerator */;
        // ...
    }
    

    This makes a great difference, since closures within the // ... will capture a new value binding in each cycle, instead of sharing the same value binding that used to be declared outside the loop.

    The catch is, if you want your code to work correctly for both older and newer compilers, you must declare your own variable inside the foreach loop:

    foreach (int value in values)
    {
        int newValue = value;
        // ...
    }
    

    The current C# 4.0 specification in Visual Studio 2010 says:

    (...) A foreach statement of the form

    foreach (V v in x) embedded-statement
    

    is then expanded to:

    {
      E e = ((C)(x)).GetEnumerator();
      try {
          V v;
          while (e.MoveNext()) {
              v = (V)(T)e.Current;
              embedded-statement
          }
      }
      finally {
          … // Dispose e
      }
    }
    

    The C# 5.0 specification in Visual Studio 2012 says:

    (...) A foreach statement of the form

    foreach (V v in x) embedded-statement
    

    is then expanded to:

    {
      E e = ((C)(x)).GetEnumerator();
      try {
          while (e.MoveNext()) {
              V v = (V)(T)e.Current;
              embedded-statement
          }
      }
      finally {
          … // Dispose e
      }
    }
    
    0 讨论(0)
  • 2021-02-07 04:57

    Note: I removed much of my original response. It was answering the wrong question. A better response follows.

    Ah, now I see what you're asking: "How does Visual Studio 2010 know to compile to C# 4 instead of C# 5 after .NET 4.5 is installed, even Visual Studio 2010 and Visual Studio 2012 use the same csc.exe and pass the same options to it?"

    @mletterle But .NET 4.5 is an in place upgrade to .NET 4. So really there is only .NET 4 present on my machine. The only possibility is that the IDE has stashed away a hidden copy of .NET 4 compiler that I cannot see.

    I'm not sure where you heard that or why you assumed that. .NET 4.5 is NOT an in-place upgrade. It is a different version of the tool. There will be differences. This is one of them.

    Update 1:

    Looks like we were using a different definition of "in-place" upgrade. My usage of "in-place" is "an upgrade that should have no discernible differences between versions." The definition given in the article you linked to uses it in a different way: "in place" in their usage is "uses the same CLR, but adds new libraries."

    Since C# 5 is different than C# 4, that change is NOT "in place" in the usage I'm familiar with.

    As a result, the difference is not the CLR you're targeting, but the language version you're using - the CLR is an "in place" upgrade (both the 4.0 CLR), but the language is not (C# 4 in VS2010, C#5 in VS2012.)

    Update 2:

    Within the .csproj file (which is actually an msbuild file managed by Visual Studio), there is an attribute that specifies the target framework. Projects made with Visual Studio 2012 have this by default:

    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    

    Whereas projects in Visual Studio 2010 that target Version 4 look like:

    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    

    This tells Visual Studio to set up the environment when building for one or the other target framework. While it looks like csc.exe is being invoked directly from a command prompt, it really isn't: the msbuild project is actually what's being processed, and it's happening in "Visual Studio"'s custom process environment.

    I can only assume the specifics of what's happening, but likely after the upgrade, having the "TargetFrameworkVersion" attribute set to v4.0 returns the environment to v4.0 during the compilation of a project targeting v4.0. On the other hand, by invoking csc.exe from the command line without the environment set up by msbuild, it uses the "defaults" for its version (which is now defaulting to C# 5) giving you the new C# 5 behavior even though you're using the VS 2010 command prompt. When you invoke the build via MSBuild, though, it knows how to return to the original C# 4 environment for the duration of the build (since MSBuild is part of the .NET tool chain, too.)

    0 讨论(0)
提交回复
热议问题