Вопрос

I need to be able to target .NET Framework 4.0 using Visual Studio 2012 and verify that my code will work correctly when deployed on our 4.0 environment (Windows Server 2003).

The multi-targeting in Visual Studio 2012 seems to work properly, but only for mscorlib.dll. When referencing any other framework DLL, for compilation you get proper errors for e.g. referencing a type that doesn't exist in 4.0, but the 4.5 version of the DLL is loaded during execution and debugging.

This makes it impossible to verify that my code will work properly in the production environment taking into account the breaking changes in the in-place upgrade that the 4.5 version of the framework did.

I made some unit tests to test the multi-targeting functionality by exercising some of the differences between 4.0 and 4.5 found on MSDN. The tests are contained in their own projects targeted at the version of the framework that they're testing. All tests should pass.

Tests against MSCORLIB

These tests pass successfully as List<string> is located in mscorlib.dll:

Framework 4.0: -passes-

[TestMethod]
public void List_Foreach_should_not_throw_if_list_is_modified() {
    var list = new List<string> { "This", "here", "be", "a", "list", "of", "strings" };

    list.ForEach((s) => {
        if (s.Equals("be", StringComparison.OrdinalIgnoreCase)) {
            list.Add(".");
        }
    });
}

Framework 4.5: -passes-

[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void List_Foreach_should_throw_if_list_is_modified() {
    var list = new List<string> { "This", "here", "be", "a", "list", "of", "strings" };

    list.ForEach((s) => {
        if (s.Equals("be", StringComparison.OrdinalIgnoreCase)) {
            list.Add(".");
        }
    });
}

Tests against other framework DLLs

These tests however do not work correctly (the 4.5 one passes, the 4.0 one doesn't) since these types are found in System.ComponentModel.Composition.dll and the 4.5 version is always loaded:

Framework 4.0 -fails, throws the exception expected on 4.5-

[TestMethod]
public void Should_be_able_to_create_a_serializer_for_MEF_catalogs()
{
    var catalog = new AggregateCatalog();
    var serializer = new XmlSerializer(typeof(AggregateCatalog));
}

Framework 4.5 -passes-

[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void Should_not_be_able_to_create_a_serializer_for_MEF_catalogs()
{
    var catalog = new AggregateCatalog();
    var serializer = new XmlSerializer(typeof(AggregateCatalog));
}

Is this as designed? It seems disjoint considering the 4.0 version of mscorlib is loaded but the 4.5 version of every other assembly.

Is there a way to get my desired functionality?

Update

Here are the solution/projects that I'm using.

Это было полезно?

Решение

Thanks for the great repro!

When looking at your project there were two things that are affecting your results leading to the behavior you are seeing:

1) When we detect a 4.0 application running under 4.5, we "shim" changed APIs to return the old 4.0 behavior when we consider it observable from reasonable (ie not contrived) application usage. For example, a 4.0 application that relied on the ability to modify the list in List.ForEach will continue to see the 4.0 behavior, regardless of whether running under 4.0 or 4.5. 4.5 applications will see the new behavior.

To determine what we consider reasonable usage, and to guide the APIs we shim, we have a compatibility team that is responsible for looking over every single "breaking" change across the entire framework, and comparing it against set of rules and guidelines that we've built up over the past 10 years.

In the project you attached, there are 5 things you are testing:

  • List.ForEach under 4.5 throws InvalidOperationException when the list is modified
  • Uri under 4.5 now preserves tailing dots in path segmants
  • Uri under 4.5 no longer escapes ? in file://-based URIs
  • Enumerable.Empty under 4.5 now guarantees that it returns the same instance (this one is a little misleading in the docs [I've filed a bug], I believe the behavior was on 4.0 that it could return two different instances the first time it was accessed by two different threads on a multi-proc'd machine at the same time)
  • MEF's catalogs are no longer XML serializable

Of these behaviors, the first three are shimmed to return the previous behavior on 4.5 when a 4.0 application is running. Whereas, the last two are not shimmed. This is because it would take very contrived application usages to be broken by the last two changes, in which case, we simply document them on that above as an FYI. For example, take the MEF catalog change, while you theoretically you could serialize these types using the XML serializer (which was unintentional, and IMHO a terrible behavior of the XML serializer) you could not do anything with the result, as it didn't deseralize to anything useful.

I'm chasing up if we can modify that page to include the list of breaking changes that are shimmed for a 4.0 application.

2) The second issue that I ran into was that 4.0 test project was incorrectly being detected as 4.5 when they were in the same run as another 4.5-based test project. You can observe this by running the 4.0 tests by themselves and the three shimed ones will pass. Run them alongside the 4.5 tests and they fail. I'm not sure where this issue is coming into play, but I've filed a bug internally and started up a thread with the responsible team to get to the bottom of it. If you would like to keep track of the issue externally, feel free to file a bug over on http://connect.microsoft.com/VisualStudio and it we'll route to the correct owners.

David Kean

CLR Team

Другие советы

As I understand it, that is exactly how it should work. There is no .NET 4.0 on your computer and in your GAC. At runtime you always have .NET 4.5 because it is in-place upgrade (installing .NET 4.5 overwrites .NET 4.0). Referenced assemblies and multi-targeting works only for IntelliSense, Object Browser and MSBuild (design time tools in general).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top