Does C# 8 annotate nullable properties and parameters?

It looks like the behaviour has changed between VS2019 Preview 1 and Preview 2, potentially due to the way that the nullable context can be changed. There's no longer a per-assembly or per-type attribute. It's possible it'll change again, of course,

In VS2019 Preview 2, each part of a member that expresses either nullable or non-nullable information (parameters and return type) is separately attributed using a NullableAttribute which is included in the assembly itself if necessary. This attribute has two constructors:

NullableAttribute(byte)
NullableAttribute(byte[])

The byte form is used when every aspect of the nullability for that parameter/return type is the same. The byte[] is used when there's a mixture of nullability for a single element, due to generics or arrays. In both cases, 1 is used for "not-nullable", 2 is used for "nullable". So for example:

public class Test
{
    public string? Foo(string input) { ... }

    public List<string>? Bar() { ... }
}

is compiled to:

public class Test
{
    [return:Nullable(2)]
    public string Foo([Nullable(1)] string input) { ... }

    [return: Nullable(new byte[] { 1, 2 })]
    public List<string> Bar() { ... }
}

This allows any code examining the assembly (whether that's the compiler using it as a reference, or other tooling) to understand the intention on a per-member basis.

I've written more about this in a blog post but that should be enough to get the gist.


Yes, if the library has been compiled using a C# 8.0 compiler with nullable reference types turned on, the compiler will be able to recognize which values were marked as nullable.

For example, consider this code:

class C
{
    string NotNullProperty { get; set; }
    string? NullProperty { get; set; }

    void M(string notNullParameter, string? nullParameter) {}
}

It compiles roughly into:

[NonNullTypes(true)]
class C
{
    string NotNullProperty { get; set; }

    [Nullable]
    string NullProperty { get; set; }

    void M(string notNullParameter, [Nullable] string nullParameter) { }
}

Notice that the nullable property and parameter are marked as [Nullable] and that the whole class is marked as [NonNullTypes(true)], indicating that the nullable reference types feature is enabled for it.

On the other hand, if the code was compiled without the feature, it will be considered "null-oblivious". This means that the compiler will not produce null-related warnings when you're working with that code.