.NET 6 code builds fine for one dev but not others

126 Views Asked by At

Our team have seen a few instances recently where code written by one specific dev doesn't build on the other devs' PCs, but we are struggling to figure out why. We all use VS2022, and the solution in question is a .NET 6 WPF application. I'm assuming the problem relates in some way to the .NET 6 SDK versions we're using, but I'm not sure where to check or how to verify this.

Here's one example of such a problem. The dev in question added an interface with internal members, along with a concrete implementation were those members were 'public'. This built fine on his PC, yet the rest of us saw this error:

Property xyz cannot implicitly implement a non-public property from interface IFoobar

Here's another (more obscure) example, which appeared in this method signature:

private bool Run(
    Isotope isotope,
    [CallerArgumentExpression(nameof(isotope))] string isotopeName = null)

Again this code built fine on that one dev's PC, while the rest of us saw this error:

Cannot resolve symbol 'isotope'

(Note, the error was reported on the second argument line).

Thoughts welcome on what the cause might be!

2

There are 2 best solutions below

5
On

Using nameof inside the an attribute on a method or parameter requires at least .NET 7 SDK (though [CallerArgumentExpression("isotope")] should work for .NET 6). See the Extended nameof scope feature spec for C# 11.

By default the latest installed SDK is used so if the newer language feature has not required changes in the CLR the project should compile and run successfully. It seems that the developer has .NET 7 or .NET 8 SDK installed (run dotnet --list-sdks to check).

You can check the SDK version used to build the project by running dotnet --version from the project folder.

Note that you can force the same SDK version to be used for build by adding global.json file to project/solution. For example the following will force the same major version:

{
  "sdk": {
    "version": "6.0.0",
    "rollForward": "latestMinor"
  }
}

Also possibly restricting C# language version used to C# 10 will do the trick also.

1
On

This is a common confusion caused by the fact that there are actually two version numbers that you need to know about when compiling a piece of C# code. The first is the most obvious - the SDK version being used for the compilation, specified by the <TargetFramework> tag in the project file. This specifies the minimum runtime version that the code will be compiled against and be able to run on.

However there is a second, equally important, version number: that of the actual C# language version being used to compile that code. This <LangVersion> tag determines what C# features are allowed to be present in the file being compiled.

The reason for this two-layered approach is that many newer C# language features are actually syntactic sugar that are transformed during compilation to something that older runtimes can understand. For example, the nameof expression that was introduced in C# 6, is transformed into a constant string at runtime, such that e.g. nameof(something) becomes "something". Since constant strings have been a fundamental runtime feature since the original version of the .NET Framework, a C# program using nameof and no other newer language features would compile to something that an ancient .NET Framework 1.0 runtime would happily execute. The .NET team felt that it didn't make sense to restrict useful syntactic sugar features to a specific SDK, therefore they introduced LangVersion as a way to allow developers targeting older runtimes to benefit from such features.

Note that the SDK-language version relationship works only one way. That is, a newer SDK can compile programs using language versions <= the version that SDK supports, but an older SDK cannot compile code using language features it does not know about.

So what should you and your team do? My suggestion would be to follow Microsoft's guidance and use a Directory.Build.props file in the root of your project's repository with a specific maximum language version (a table of these versions can be found on that page) that you want your developers to write C# code in (and ensuring that all developers have an SDK version installed that supports that langver). That way, if a dev tries to use a newer C# feature that others may not support, they will get a compile-time error on their machine and should never check that code in.