Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET target framework compatibility and the compiler - on .NET 4.5 or higher

I'm fairly experienced in .NET development but today I was forced to wrap my head around something I'd never thought about before:

How do the installed .NET Framework, the .NET Framework target in Visual Studio and the C# compiler work together?

Concrete example: The System.dll contains the enum System.Net.SecurityProtocolType. On .NET 4.5 this enum contains the members SSl3 , Tls, Tls11, and Tls12. With .NET 4.7, the member SystemDefault was added.

So, targeting .NET 4.7.x, this code compiles fine:

var p = SecurityProtocolType.SystemDefault;

However, when I target .NET 4.5.x, this code does not compile (as one would expect).

What puzzles me here is why this works considering that .NET 4.7 is an in-place update to .NET 4.5 (i.e. when installing .NET 4.7, the System.dll of .NET 4.5 is replaced with the one of .NET 4.7).

How does the compiler know that I can't use SystemDefault on .NET 4.5 but can use it on 4.7? Is this done via some kind of API file known to the compiler?

Side fact: When I target .NET 4.5 and have .NET 4.7 installed, a call to Enum.GetValues(typeof(SecurityProtocolType) will give me SecurityProtocolType.SystemDefault. So I'm fairly certain that my .NET 4.5 application uses the .NET 4.7 System.dll.

like image 822
Sebastian Krysmanski Avatar asked Jan 29 '18 14:01

Sebastian Krysmanski


2 Answers

How does the compiler know that I can't use SystemDefault on .NET 4.5 but can use it on 4.7? Is this done via some kind of API file known to the compiler?

Yes, I'd expect it to be done via the reference assemblies. A reference assembly is an assembly which includes just the accessible API definitions, effectively.

On my Windows machine, these are in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework

like image 177
Jon Skeet Avatar answered Oct 22 '22 03:10

Jon Skeet


When you specify a target of .NET Framework 4.5, you are specifying the interface surface of that API. The compiler uses this exact version to determine what types are available.

When .NET Framework 4.7 runtime exists on the target machine, the types are forwarded from 4.5 to 4.7. But this is just the runtime behavior. It doesn't change the fact the target was .NET Framework 4.5 when the application was compiled. Keep in mind when the assembly is deployed on the target machine, it is already compiled to intermediate language. The compiler is not involved at all during runtime and therefore cannot dynamically change the target framework.

As for your side fact, that is the runtime behavior of Reflection that works that way because the runtime framework it is using is 4.7.

like image 21
NightOwl888 Avatar answered Oct 22 '22 02:10

NightOwl888