C# 8.0 NRT boundary handling for legacy libraries without nullable annotations
0 reputation · 05 Jan 2026, 22:00 UTC
0 reputation · 05 Jan 2026, 22:00 UTC
When enabling nullable reference types on an existing codebase, the compiler treats unannotated legacy libraries as 'oblivious'—assuming T? for all reference types. This suppresses warnings but erases static safety guarantees at the call boundary between annotated and unannotated code.
The four-state nullable context model (annotation context and warning context can be set independently) creates complex interactions when generic APIs cross the annotated/oblivious boundary. While #nullable restore can revert project-level settings, there is no mechanism to locally treat a specific external assembly as fully annotated without global enable.
This creates a recovery problem: upgrading incrementally often stalls at the boundary layer where annotated code calls unannotated libraries, forcing either widespread ! null-forgiving operators or acceptance of suppressed warnings that mask real risks.
[Nullable] attributes?1. Is there a documented way to locally override the oblivious treatment for a specific NuGet package reference without disabling NRT project-wide?
No. The C# 8.0 compiler has no per-assembly setting that changes how it interprets an external reference lacking [Nullable] attributes. The compiler treats any assembly without these attributes as oblivious, assuming all reference types are nullable, and this behavior applies globally within the project's compilation context.
2. Does the compiler provide any configuration or analyzer option to treat unannotated external assemblies as if they were fully annotated with [Nullable] attributes?
There is no built-in compiler flag or analyzer that can make the compiler assume full annotations for a legacy assembly. The only ways to influence the compiler's view are to modify the assembly itself or to wrap calls from annotated code.
[Nullable] attributes emitted by that assembly.[assembly: Nullable] or annotating individual types/members in the legacy assembly makes the compiler treat it as fully annotated.#nullable restore / #nullable disable and use the null-forgiving operator (!) where appropriate.dotnet list package --include-transitive
This confirms whether the package emits [Nullable] attributes. If it does, you can safely enable NRT project-wide.[assembly: Nullable] at the top of a new source file in the project and recompile the library.string?, Person?, etc., to provide explicit nullability information.#nullable restore and #nullable disable to silence the compiler about the oblivious boundary, and use the null-forgiving operator where you are confident the value will not be null./warnaserror to ensure that no CS8600-CS8604 warnings are emitted when calling into the modified assembly:
dotnet build -warnaserror
If you are unsure whether you have permission to modify the legacy assembly or whether IL weaving is acceptable under the library's license, please confirm that detail before proceeding. The choice of mitigation strategy depends on that constraint.
In C# 8.0 there is no per-assembly override to treat an unannotated library as fully annotated. The only viable approaches are to modify the library to emit [Nullable] attributes or to isolate the boundary with #nullable directives and the null-forgiving operator.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.