Detect Target Framework Version at Compile Time

Detect target framework version at compile time

The linked SO question with 'create N different configurations' is certainly one option, but when I had a need for this I just added conditional DefineConstants elements, so in my Debug|x86 (for instance) after the existing DefineConstants for DEBUG;TRACE, I added these 2, checking the value in TFV that was set in the first PropertyGroup of the csproj file.

<DefineConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0' ">RUNNING_ON_4</DefineConstants>
<DefineConstants Condition=" '$(TargetFrameworkVersion)' != 'v4.0' ">NOT_RUNNING_ON_4</DefineConstants>

You don't need both, obviously, but it's just there to give examples of both eq and ne behavior - #else and #elif work fine too :)

class Program
{
static void Main(string[] args)
{
#if RUNNING_ON_4
Console.WriteLine("RUNNING_ON_4 was set");
#endif
#if NOT_RUNNING_ON_4
Console.WriteLine("NOT_RUNNING_ON_4 was set");
#endif
}
}

I could then switch between targeting 3.5 and 4.0 and it would do the right thing.

Detect the C# version at compile time

The nameof() operator is meant to reduce maintenance: using it you don't have identifiers hidden in strings, so when you rename a variable, parameter or member, the place where you use it (for example an ArgumentNullException(nameof(paramName))) will be updated when you refactor the paramName name.

Now using your approach, you're effectively doubling your maintenance surface instead of reducing it (as you now have both the string variant and the nameof() version, both of which having to be maintained), negating the use of nameof() altogether.

So if you want to support older C# versions, stick to features that work in those versions: use identifiers in strings instead.

How to get the version of the .NET Framework being targeted?

That's simple - check the TargetFrameworkAttribute:

var targetFrameworkAttribute = Assembly.GetExecutingAssembly()
.GetCustomAttributes(typeof(System.Runtime.Versioning.TargetFrameworkAttribute), false)
.SingleOrDefault();

Retrieve Target Framework Version and Target Framework Profile from a .Net Assembly

If you would be satisfied with the version of the CLR that compiled the assembly, you can use the Assembly.ImageRuntimeVersion property. According to MSDN, that property:

representing the version of the common language runtime (CLR) saved in the file containing the manifest.

and

By default, ImageRuntimeVersion is set to the version of the CLR used to build the assembly. However, it might have been set to another value at compile time.

Of course, that doesn't give you the specific version of the .NET Framework (for example: .NET Frameworks 2, 3.0 and 3.5 are all on the 2.0 CLR).

If the CLR version isn't sufficient, you could to try to 'estimate' (guess intelligently) what version it must be based on the assemblies it references. For .NET 1 and 4, the CLR version should be enough. However, if the CLR version was 2.0, you wouldn't know if that meant 2.0, 3.0, or 3.5 so you could try some more logic. For example, if you saw that the Assembly referenced System.Core (using Assembly.GetReferencedAssemblies()) then you would know that the version is 3.5 since System.Core was new in 3.5. That's not exactly rock-solid since the assembly in question might not use any types from the Assembly so you wouldn't be able to catch that. To try to catch more cases, you could loop through all the referenced assemblies and check their version numbers - maybe filtering to just assemblies that start with System to avoid false positives with other libraries. If you see any System.* assemblies referenced that have a version of 3.5.x.x, then you can also be pretty sure it was built for 3.5.


As you've noticed, I don't believe the TargetFrameworkProfile escapes past Visual Studio. However, if there happens to be an app.config file for the application, Visual Studio may have put the target framework in there. For example, if you set project to use the 4.0 Client Profile, Visual Studio creates an app.config like this:

<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
</startup>
</configuration>


Related Topics



Leave a reply



Submit