'Can I determine the .NET SDK version used when building from a .csproj or .targets file?

This is mainly to try to work around an annoying coupling of the .Net analyzers to the version of Visual Studio that the .NET SDK version has an affinity to.

If I use the MSBuild under my Visual Studio 2019 v16.9.X installation (the LTS version that we are currently using), and it tries to build my csproj with the 5.0.404 .NET SDK (because I also have that SDK installed), I will get a lot of errors, because the analyzers in that version of the SDK want to load VS 16.11.X versions of assemblies that are already loaded by the 16.9.X compilers.

30>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\Roslyn\csc.exe [...]
30>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.UseExplicitTupleName.UseExplicitTupleNameDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\5.0.404\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.11.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
30>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.UseSystemHashCode.UseSystemHashCodeDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\5.0.404\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.11.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
30>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.MakeFieldReadonly.MakeFieldReadonlyDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\5.0.404\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.11.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
30>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.CSharp.UseNullPropagation.CSharpUseNullPropagationDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\5.0.404\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CSharp.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.11.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
[...]

I would like to specify the compiler versions to use explicitly, depending on the .NET SDK version that is used to build.

For instance, if it is in the 5.0.2XX feature band, I would <PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="3.9.0" />, but if it's in the 5.0.4XX band, I would <PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="3.11.0" />.

To do this, I need to be able to tell which SDK version is being used.



Solution 1:[1]

A good place to start looking for your answer is to run msbuild /bl on your csproj.

That will create a msbuild.binlog file which can be opened with Microsoft's MSBuild Log Viewer.

From the log viewer, you can easily look at all the properties and their values visible to your project during build.

Once you've found a proper match, you can set a Condition on each PackageReference item.

Just be mindful that it might screw-up with Inteli-Sense when inside Visual Studio, so maybe have one of the PackageReferences as default, just in case.

Example: The name of the property you're looking for is MyProperty

Then:

<PackageReference Condition="'$(MyProperty)'.StartsWith('5.0.2')" Include="Microsoft.Net.Compilers.Toolset" Version="3.9.0" />
<PackageReference Condition="'$(MyProperty)'.StartsWith('5.0.4')" Include="Microsoft.Net.Compilers.Toolset" Version="3.11.0" />

Solution 2:[2]

As you figured it out, the NETCoreSdkVersion property contains the .NET SDK version.

And here's an example to use it in combination with the [MSBuild]::VersionGreaterThanOrEquals() function.

<PropertyGroup Condition="$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '6.0'))">
  <UseCurrentRuntimeIdentifier>true</UseCurrentRuntimeIdentifier>
</PropertyGroup>

<PropertyGroup Condition="!$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '6.0'))">
  <RuntimeIdentifier Condition="$([MSBuild]::IsOSPlatform('Linux'))">linux-x64</RuntimeIdentifier>
  <RuntimeIdentifier Condition="$([MSBuild]::IsOSPlatform('OSX'))">osx-x64</RuntimeIdentifier>
  <RuntimeIdentifier Condition="$([MSBuild]::IsOSPlatform('Windows'))">win-x64</RuntimeIdentifier>
</PropertyGroup>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Captain
Solution 2