I’ve experienced the same behavior in Unity 2022 and 2023.
Even if I select Api Compatibility to netstandard2.1 and everywhere else I can find it, the generated csproj uses the Full Framework 4.7.1.
Because of this, nullable references Intellisense doesn’t work, because VS 2022 thinks it’s targeting a classic Framework project; however, the Unity Editor can use compiler flags to enable this behavior in the build phase, and gives out errors when dereferencing potential nullable references, but the Intellisense in VS 2022 is none the wiser.
I’ve looked for potential solutions and tried them (using compiler flags -nullable:enable and -warnaserror:Nullable, adding a Directory.Build.props file in the root of the project), but the root cause of it seems to be the fact that the csproj is generated with Framework 4.7.1 instead of netstandard2.1
Any help would be appreciated. Thanks in advance.
Edit: I have used Unity 2022.3.16f1, Unity 2023.2.5f1, and the latest (i think) VS editor package, but I’m unusure where to check its version. I also have a plethora of dotnet SDKs installed locally, including the core versions and the full framework ones.
Could you provide a code example that does or should trigger this? Because nullable references is a big field. Could be the ? and ?? operators, or the [NotNull] attribute or just static code analysis output.
Just FYI I do get “potential null reference” indicators whereever appropriate no matter which Unity version, but I’m also using an IDE that’s far superior to VS. 
[SerializeField]
private GameObject? _laserPrefab;
// Update is called once per frame
void Update()
{
CalculateMovement();
if(Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Space key pressed and will create: " + _laserPrefab.name);//this fails on compile inside Unity Editor when the proper compiler flags are given, but Intellisense doesn't shows it as an error inside VS2022
if (_laserPrefab != null)
{
if (Debug.isDebugBuild)
{
Debug.Log("Space key pressed and will create: " + _laserPrefab.name);
}
Instantiate(_laserPrefab, transform.position, Quaternion.identity);
}
}
}
As a side note, for other ppl wanting to enable nullable references and forcing intellisense to treat nullable warnings as errors, you can drop this file inside the Assets\Editor folder to rewrite the csproj file generated by Unity to trick VS2022 Intellisense into thinking it’s working with a netstandard2.1 csproj:
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using UnityEditor;
public class CSProjPostprocessor : AssetPostprocessor
{
private const string SCHEMA = @"http://schemas.microsoft.com/developer/msbuild/2003";
private const string ASSEMBLY_NAME = "AssemblyName";//XML category for assembly
private const string ASSEMBLY_CSHARP_RUNTIME = "Assembly-CSharp";//value for assembly name
private const string TARGET_FRAMEWORK_VERSION = "TargetFrameworkVersion";//XML category for .net framework
private const string FRAMEWORK_EXPECTED = "v4.7.1";//old value for framework
private const string FRAMEWORK_DESIRED = "netstandard2.1";//new value for framework
class Utf8StringWriter : StringWriter
{//to allow UTF8 saving
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
}
public static string OnGeneratedCSProject(string path, string content)
{
var document = XDocument.Parse(content);
var assemblyName = document.Descendants(XName.Get(ASSEMBLY_NAME, SCHEMA)).FirstOrDefault();
if (null != assemblyName && assemblyName.Value.Contains(ASSEMBLY_CSHARP_RUNTIME))
{
var target = document.Descendants(XName.Get(TARGET_FRAMEWORK_VERSION, SCHEMA)).FirstOrDefault();
if (null != target && target.Value.Contains(FRAMEWORK_EXPECTED))
{
target.Name = target.Name.Namespace + "TargetFramework";
target.SetValue(FRAMEWORK_DESIRED);
target.AddAfterSelf(new XElement(target.Name.Namespace + "Nullable", "enable"),
new XElement(target.Name.Namespace + "WarningsAsErrors", "Nullable"));
}
}
var str = new Utf8StringWriter();
document.Save(str);
return str.ToString();
}
}
The code was adapted from: Any way to force .net 4.6.1? 4.7.1 unavailable for OS
Edit: it would seem other have noticed this issue of generating a 4.7.1 framework csproj instead of a netstandard2.1 csproj, and yes, it is a bug apparently: Getting started with a .NET 6.0 project in latest Alpha 2022.2.a13 is impossible? with no fix as of yet. Edit 2: this is a thread for an older version, and wasn’t the root cause of my issue, and in consequence, not the bug I was trying to fix.
This might be an interesting read as to what to do next in order to support nullable reference type attributes: How to use Nullable Reference Types in .NET Standard 2.0 and .NET Framework - Meziantou's blog
[SerializeField] private GameObject? _laserPrefab;
Nullable support aside, I would call this bad practice.
There is nothing in the Inspector informing the user whether a reference can be null or must be assigned. An unassigned Inspector reference, to my and most minds, is indicating that there is something missing and that it will be an issue.
There are many ways to highlight nullable in the Inspector, the easiest being a specific [Header(„Nullable“)] attribute for nullable refs but that may tear the fields apart that belong together. Alternatives: subclasses, custom property drawer, custom Inspector which draws different items based on a dropdown selection perhaps, certainly more.
If the property/field can be null, then it must declared as nullable, as such when a user forgets to set it in the editor, the language features guide us to also treat this case with a relevant error message. If there is a way to validate required properties/fields before running a project, then that would be something of interest.
Also, I’ve found out the issue:
IF VS2022 is selected as an IDE inside Unity Editor, then LegacyStyleProjectGeneration is used to generate the csproj com.unity.ide.visualstudio/Editor/VisualStudioForWindowsInstallation.cs at master · needle-mirror/com.unity.ide.visualstudio · GitHub
The solution to my problem is to choose VS Code as an IDE inside Unity Editor, which will use SdkStyleProjectGeneration com.unity.ide.visualstudio/Editor/VisualStudioCodeInstallation.cs at b28f5a3cbf26211491a4f3db4561300da94383a9 · needle-mirror/com.unity.ide.visualstudio · GitHub and then open with VS2022 manually. The generated csproj uses netstandard2.1 as expected, and is valid (unlike my hacky solution from above).
1 Like