Never forget a #if when multi-targeting .NET libraries or applications

 
 
  • Gérald Barré

It's very easy to multitarget a library in the csproj. All you need to do is listing all target frameworks in the TargetFrameworks element:

csproj (MSBuild project file)
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net5.0;netstandard2.1;netstandard2.0;net461</TargetFrameworks>
  </PropertyGroup>
</Project>

Then, you may have different implementations in the code depending on the target framework. When MSBuild compiles your project it automatically adds a symbol you can use in #if. For instance, you can use #if NET461 ... #endif to compile a code specific to the net461 target.

C#
#if NET461
// Code specific to net461
#elif NETSTANDARD2_0 || NETSTANDARD2_1
// Code specific to netstandard2.1 or netstandard2.0
#else
// Code specific to other frameworks
#endif

The pattern I often see in codebases is:

C#
#if NET5_0
// Optimized code that uses .NET 5.0 API
#else
// Legacy implementation for previous frameworks
#endif

This code is fine until you add new target frameworks. Indeed, you may want newer frameworks to use the optimal case, but it may end up using the legacy implementation case. Finding all #if to update is error-prone. An easy way to prevent that is to add a #else and report an error using #error.

C#
#if NET5_0
// Optimized code that uses .NET 5.0 API
#elif NETSTANDARD2_0 || NETSTANDARD2_1
// Legacy implementation for previous frameworks
#else
// Prevent compilation for unknown target frameworks
#error Target Framework not supported
#endif

If you add a new target, you'll get a compilation error. Note that the error list window shows the target where the error is reported (netcoreapp3.1 in this case).

You can now check all locations that need to be updated when adding a new TFM.

Future versions of .NET may provide OR_GREATER preprocessor symbols for TFMs to create forward-compatible #if. This should allow using preprocessor symbols such as NET5_0_OR_GREATER. Here's a link to the accepted proposal "OR_GREATER preprocessor symbols for TFMs proposal"

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub