Giter Site home page Giter Site logo

manuelroemer / nullable Goto Github PK

View Code? Open in Web Editor NEW
181.0 13.0 8.0 107 KB

A source code only package which allows you to use .NET's nullable attributes in older target frameworks like .NET Standard 2.0 or the "old" .NET Framework.

Home Page: https://www.nuget.org/packages/Nullable

License: MIT License

C# 100.00%
source compiletime csharp null nullable attribute allownull disallownull doesnotreturn doesnotreturnif maybenull maybenullwhen notnull notnullifnotnull notnullwhen membernotenull membernotnullwhen polyfill

nullable's Introduction

Nullable Nuget

Use .NET Core 3.0's new nullable attributes in older target frameworks.

🏃 Quickstart   |   📚 Guides   |   📦 NuGet


You may also want to check out my IsExternalInit project which provides support for C# 9's init and record keywords for older target frameworks.


With the release of C# 8.0, support for nullable reference types has been added to the language. Futhermore, .NET Core 3.0 added new nullable attributes like the AllowNullAttribute which are sometimes required to exactly declare when and how null is allowed in specific code sections.

Unfortunately, these attributes are not available in older target frameworks like .NET Standard 2.0 which makes annotating existing code harder. Luckily, this problem can be solved by re-declaring the attributes as internal classes - the C# compiler will still use them for generating warnings, even though the target framework doesn't support these attributes by itself.

This repository hosts the code for the "Nullable" NuGet Package which, when referenced, adds support for these attributes.

The code for these attributes is added at compile time and gets built into the referencing project. This means that the resulting project does not have an explicit dependency on the Nullable package, because the attributes are not distributed as a library.

Futhermore, the code only gets added to the project if the nullable attributes are not already supported by the target framework. The images below show an example - in the library which targets .NET Standard 2.0, the attributes have been added during the compilation. That is not the case for the library targeting .NET Standard 2.1, because the attributes are available through the .NET BCL there. This allows you to easily multi-target your projects without having to change a single line of code.

.NET Standard 2.0 .NET Standard 2.1
.NET Standard 2.0 .NET Standard 2.1

Compatibility

Nullabe is currently compatible with the following target frameworks:

  • .NET Standard >= 1.0
  • .NET Framework >= 2.0

Please have a look at the guides for additional information on how to install the package for your target framework.

Quickstart

⚠️ Important:
You must use a C# version >= 8.0 with the Nullable package - otherwise, your project won't compile.

The steps below assume that you are using the new SDK .csproj style. Please find installation guides and notes for other project types (for example packages.config) here.

  1. Reference the package
    Add the package to your project, for example via:

    Install-Package Nullable
    
    --or--
    
    dotnet add package Nullable
  2. Ensure that the package has been added as a development dependency
    Open your .csproj file and ensure that the new package reference looks similar to this:

    <PackageReference Include="Nullable" Version="<YOUR_VERSION>">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    
    <!-- This style also works, but is not automatically used by .NET: -->
    <PackageReference Include="Nullable" Version="<YOUR_VERSION>" PrivateAssets="all" />

    This is especially important for libraries that are published to NuGet, because without this, the library will have an explicit dependency on the Nullable package.

  3. Build the project
    Ensure that the project compiles. If a build error occurs, you will most likely have to update the C# language version (see next step).

  4. Enable Nullable Reference Types
    Still in your .csproj file you need to activate the feature to fully use it. The following activation sample is what seems to be the most common use case. But do not hesitate to look at my guides for other considerations.

    <PropertyGroup>
      <!-- Your desired target frameworks. -->
      <TargetFrameworks>net472;netstandard2.0;netstandard2.1;netcoreapp3.0</TargetFrameworks>
      
      <!-- The C# language version to use. Must be at least 8.0 (other suggestions: 9.0, latest, preview).-->
      <LangVersion>8.0</LangVersion> <!-- or --> <LangVersion>latest</LangVersion>
        
      <!-- Enable nullable reference types. You can also use "annotations" instead of "enable"
           to prevent the compiler from emitting warnings. -->
      <Nullable>enable</Nullable>
    </PropertyGroup>
  5. For WPF users:
    There have been issues with WPF projects in the past which resulted in compilation errors, however these have been fixed with the .NET 5.0.102 SDK. To get Nullable working with your WPF project, ensure that you are using an SDK >= 5.0.102 SDK and then add the following configuration to your .csproj file:

    <UseWPF>true</UseWPF>
    <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>

You should now be ready to use Nullable Reference Types and the corresponding attributes even when targeting legacy frameworks.

Compiler Constants

The included C# file makes use of some compiler constants that can be used to enable or disable certain features.

NULLABLE_ATTRIBUTES_DISABLE

If the NULLABLE_ATTRIBUTES_DISABLE constant is defined, the attributes are excluded from the build. This can be used to conditionally exclude the attributes from the build if they are not required.

In most cases, this should not be required, because the package automatically excludes the attributes from target frameworks that already support these attributes.

NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE

Because the attributes are added as source code, they could appear in code coverage reports. By default, this is disabled via the ExcludeFromCodeCoverage and DebuggerNonUserCode attributes.

By defining the NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE constant, the ExcludeFromCodeCoverage and DebuggerNonUserCode attributes are not applied and the nullable attributes may therefore appear in code coverage reports.

Building

Because the package consists of source files, building works differently than a normal .NET project. In essence, no build has to be made at all. Instead, the *.cs files are packaged into a NuGet package via a .nuspec file.

The solution contains a _build project which automatically performs these tasks though. You can then find the resulting NuGet package file in the artifacts folder.

Contributing

I don't expect this package to require many changes, but if something is not working for you or if you think that the source file should change, feel free to create an issue or Pull Request. I will be happy to discuss and potentially integrate your ideas!

License

See the LICENSE file for details.

nullable's People

Contributors

dependabot[bot] avatar gtbuchanan avatar manuelroemer avatar mnivet avatar tyrrrz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nullable's Issues

[Solution] Nullable attributes are not discovered in WPF projects

I have a relatively complex solution with lots of legacy stuff, but I did manage to modernize some of the assemblies to the Sdk style and PackageReference instead of packages.config. I can add your NuGet package and then write code like this, in .NET Framework 4.7.2:

    public bool TryGetExistingFavorite(ContactRecord record, [NotNullWhen(true)] out Favorite? favorite)
    {
        favorite = _Favorites.FirstOrDefault(f => f.CID == record.ID);

        return favorite != null;
    }

This looks great during design-time builds. But when I actually do a full build, I get an error that the attributes can't be found:

1>…path…\Favorites\FavoritesRepository.cs(108,68,108,79): error CS0246: The type or namespace name 'NotNullWhenAttribute' could not be found (are you missing a using directive or an assembly reference?)
1>…path…\Favorites\FavoritesRepository.cs(108,68,108,79): error CS0246: The type or namespace name 'NotNullWhen' could not be found (are you missing a using directive or an assembly reference?)
1>Done building project "MyProject_hh54oelh_wpftmp.csproj" -- FAILED.

I've tried both a regular reference like so:

    <PackageReference Include="Nullable" Version="1.2.1" />

And the adjusted one from the README:

    <PackageReference Include="Nullable" Version="1.2.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>

I think the …**wpftmp**.csproj portion may be a clue. However, with a test project that also contains WPF, I wasn't able to reproduce the issue.

Add support for [MemberNotNull] and [MemberNotNullWhen]

New nullability attributes are currently being introduced (see https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs).

These should be added to Nullable as soon as:

  • They are available in a .NET release/are finalized and no longer prone to change.
  • It is verified that the compiler also supports them when they are declared as internal attributes (otherwise adding them to this package has no benefit).

CS0246 build errors on .NET 6.0.300 SDK

After installing the .NET 6.0.300 SDK, doing dotnet build --no-incremental on a project using this library gives errors such as:

error CS0246: The type or namespace name 'NotNullWhen' could not be found

Minimal Reproduction

MyApp.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <LangVersion>8</LangVersion>
    <Nullable>annotations</Nullable>
    <TargetFrameworks>net6.0;net48</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
  </ItemGroup>

</Project>

Program.cs

using System;
using System.Diagnostics.CodeAnalysis;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            if (Test(out var value))
            {
                Console.WriteLine(value);
            }
        }

        private static bool Test([NotNullWhen(true)] out string? value)
        {
            value = "Hello World!";
            return true;
        }
    }
}

Compile with dotnet build --no-incremental:

C:\Users\mattj\Code\MyApp>dotnet build --no-incremental
Microsoft (R) Build Engine version 17.2.0+41abc5629 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  All projects are up-to-date for restore.
C:\Users\mattj\Code\MyApp\Program.cs(16,35): error CS0246: The type or namespace name 'NotNullWhenAttribute' could not be found (are you m
issing a using directive or an assembly reference?) [C:\Users\mattj\Code\MyApp\MyApp.csproj]
C:\Users\mattj\Code\MyApp\Program.cs(16,35): error CS0246: The type or namespace name 'NotNullWhen' could not be found (are you missing a 
using directive or an assembly reference?) [C:\Users\mattj\Code\MyApp\MyApp.csproj]
  MyApp -> C:\Users\mattj\Code\MyApp\bin\Debug\net6.0\MyApp.dll

Build FAILED.

Workaround

Install the previous 6.0.203 SDK, and force the project to use it by adding a global.json file with the following:

{
  "sdk": {
    "version": "6.0.203"
  }
}

Then the project builds just fine with dotnet build --no-incremental.

This might be an upstream problem with .NET, but I haven't dug deep enough to figure out what it might be.

Reference problem in WPF environment

When using the library in a WPF environment it´s not possible to add a reference to the included types.
I found that problem with my own library and was hoping, that you solved it somehow but I can recreate the issue with your project.

I created a sample project to recreate the issue.
The branch nullable shows the problem with your library.

Its a simple console application that also includes a WPF User Control.
image

using System;
using System.Diagnostics.CodeAnalysis;

namespace TheWPFClient
{
    class Program
    {
        [AllowNull] private readonly string OptionalValue;

        static void Main(string[] args)
        {
            Console.WriteLine("Hello beatiful World!");
        }
    }
}

When compiling the code that build error accours:

Program.cs(8,10,8,19): error CS0246: The type or namespace name 'AllowNullAttribute' could not be found (are you missing a using directive or an assembly reference?)
Program.cs(8,10,8,19): error CS0246: The type or namespace name 'AllowNull' could not be found (are you missing a using directive or an assembly reference?)

If you delete the usercontrol the error is gone.

Use #pragma warning restore instead of #pragma warning enable

While this is most likely not going to cause problems, it is good practice to use #pragma warning restore instead of #pragma warning enable. In the nullable files, enable is used at the moment:

This was an oversight and should be changed.
If there are no complaints/problems due to this in the meantime, I will delay the fix until the next release of the package.

Nullable's XML documentation leaks into XML docs of referencing libraries

Every library that references Nullable and has XML documentation finds the latter "polluted" by the documentation for Nullable's attributes.

Although I understand that Intellisense is nice to have, I'd rather push F1 when I need an explanation on some attribute than have the attributes' documentation injected into every NuGet package I produce. Not to mention automatically-generated online docs!

I propose that XML documentation be removed completely from Nullable, as the inconveniences it brings to referencing libraries outweigh its usefulness.

Internal attributes prevent build on .NET4.8

I'm trying to decorate a method parameter with [AllowNull]. Inside the IDE, visual studio recognizes it and works fine, but when I go to compile the project I can not - it says the attribute is internal not public

Support for netstd < 2.0

Just by glancing at the project I can't see any indication if this will work in a project that targets, for example, .NET Standard 1.1.
Does it? Are there technical limitations related to supporting lower versions?

Can't build on older targets without explicit LangVersion

I'm trying to create a NuGet package which contains 100% manual NRT attributes (with no C# 8.0 syntax) so that I can multitarget netstandard2.0 and netstandard2.1, remain in an MS-supported configuration (employer requirement), and get correct nullability warnings in projects which use C# 8.0+.

When I try to build against netstandard2.0, I get build errors on the generated .cs files in the obj folder because they include the #nullable preprocessor statement. If this preprocessor statement was not present (and the attributes had their own explicit annotations, if that's possible/needed), the files would otherwise compile.

Do you think you could make this change?

[Discussion] Installation Error when using NuGet's packages.config file

Hi, I wanted to give this package a try but during installation VS gives met this error:

Could not install package 'Nullable 1.1.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.7.2', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

Incremental build is slowed by timestamps of generated source file

Particularly when setting:

    <ProduceReferenceAssembly>true</ProduceReferenceAssembly>

We expect that when A references B and B changes in a way that does not impact its public API, then A does not need to be recompiled. But when A has a package reference to Nullable, it recompiles anyway for no good reason, making incremental builds slower.

Input file "C:\git\lib.template\obj\Library.Tests\Debug\netcoreapp3.1\NuGet\8ED094343F5007F7EC35D088A29F28BB2E4E7756\Nullable\1.3.0\Nullable/MemberNotNullAttribute.cs" is newer than output file "C:\git\lib.template\obj\Library.Tests\Debug\netcoreapp3.1\Library.Tests.xml".

image

Can you fix this by ensuring the timestamp is not updated on this file unnecessarily?

You can test this for yourself, and verify the effectiveness of your fix, using my template repo as follows:

git clone https://github.com/AArnott/Library.Template.git
cd Library.Template
.\init[.ps1]
dotnet build

Then make a change to Calculator.cs that does not impact the public API. Perhaps this:

-        public static int Add(int a, int b) => a + b;
+        public static int Add(int a, int b) => a + b + 1;

Then run:

dotnet build -bl

Open up the msbuild.binlog (in the https://msbuildlog.com viewer) and search for $task csc to see how many times the compiler actually ran. We want to see it just once. When Nullable is not referenced, this happens. But when it is referenced, we see 4.

Automatically exclude attributes from style/code analysis

When installing this package, its item is added to the compilation. If a style rule does not match with the code style in the code file, an analysis error might stop compilation.

To repro, add this to a project's .editorconfig:

# IDE0040: Add accessibility modifiers
dotnet_diagnostic.IDE0040.severity = error

(this setting will cause a build error if an accessibility modifier is added which is already the default for it, like adding internal to a class).

After installing the package, now you'll get the expected build error:

Severity	Code	Description	Project	File	Line	Suppression State
Error	IDE0040	Accessibility modifiers required	[ProjectName]	[ProjectPath]\obj\3.8.0\Debug\NuGet\3D28A4393902596C02B027108469F4ED40AA07C9\Nullable\1.0.0\Nullable\NullableAttributes.cs	46	Active

I have learned that this can be avoided by simply adding this to the code files somewhere (near the top?): // <auto-generated/>

That eliminates the (spurious) error shown above.

Can you add package to support InAttribute for netstandard1.0 as target

When I use ref readonly and in parameter in package for netstandard1.0 target, compiler return error Predefined type 'System.Runtime.InteropServices.InAttribute' is not defined or imported.

Can you add new package like Nullable to support ref readonly and in parameter for netstandard1.0.

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.