Can you run code compiled for .NET 4.6.2 on .NET 4.0?
TL;DR: Yes. Yes you can.
If you would have asked me a week ago I would have said ‘No’. That’s also the answer I, incorrectly, gave when this question was asked in a Reddit thread. The question was regarding access to the
System.ServiceProcessesServicesController.StartType property (docs) if the framework installed was at least .NET 4.6.1 since the property does not exist in earlier framework versions.
My answer was that this is not possible as the code would not compile if the property being accessed did not exist. But what if the code was compiled with a target framework where the property exist and then ran on a framework where it does not? Can you even do that?
It turns out that you can by changing some values in the
supportedRuntime element in app.config.
version specifies the .NET Framework major version. All 4.x versions are in-place updates meaning that they will replace any earlier 4.x version installed on the machine. The version inside
sku is used as a hint to the .NET loader on which framework version to load the application with. The latest installed version of the framework will always be used if an older version is specified.
If I try to run a program with the above app.config on a machine that does not have .NET 4.6.2 installed I will be asked to install it.
However if I change the sku version to the latest version installed on my machine
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
it will gladly run the program as long as I don’t load something that is not supported in the installed framework into the current scope.
If I try load the
StartType property into scope the program will crash with a runtime exception.
As all 4.x versions are in-place updates they are IL compatible which means that they can all understand the same underlying code format.
So as long as I don’t access the property I’m good? No not exactly. The program will crash when the property that does not exist is loaded into scope. To illustrate I’ll give two code examples.
The first example accesses the property in a different method. This code does not crash.
public class Program
If I inline the property accessor, the program will crash on start.
public class Program
Async await was introduced in C# 5.0 and .NET framework 4.5. Clearly the above trick can’t work if you have async methods?
Actually it does as long as you don’t load the call to the async method into scope. If you do, your program will crash.
So production ready and let’s ship it?
You probably should not use this in production unless you know exactly what you are doing. The original question was regarding a single property to know how a Windows service was configured to start. That is probably safe unless your code uses other libraries that use code compiled for a later framework version which does not take this hack into consideration. I would argue that most libraries does not :)
What is needed for this to work?
- Code compiled for a target framework where the property exist, e.g. 4.6.1.
- Latest framework installed must be lower than the target framework compiled for, e.g. 4.0 or 4.5.
- Change the sku version/loader hint to the installed framework version.
The source code is available on our Github: https://github.com/AdviseSolutions/RunCodeFor462On40