0
var x = something.Relation.Where(x => ...); // no warning here

I am wondering how to tell the compiler that a certain property will never be null, despite the compiler does not see any initialization code. Currently the compiler issues a warning:

Non-nullable property is uninitialized. Consider declaring the property as nullable

My most frequent cases are entities initialized by an ORM framework. Either, they are auto-instantiated by the ORM when the entity instance is created, or a post-processor analyzes the assembly and injects initialization code. Hence, when a new instance is created by a simple new MyEntity() certain properties of reference types are already non-null, despite the compiler doesn't see that.

Case 1: Relationships to other entities

The [Association] attribute is handled in a specific way by the ORM, ensuring properties of EntitySet<T> types are auto-initialized to actual instances of these collections.

public class MyEntity : Entity
{
    // this reference will never be null, warning here
    [Field]
    [Association]
    public EntitySet<OtherEntity> Relation { get; set; } // * the setter might be omitted

    // this reference will never be null, warning here
    [Field]
    [Association]
    public ParentEntity Parent { get; set; }

    // here it is clearly annotated that this reference may be null, no warning, obviously
    [Field]
    [Association]
    public OtherEntity? Relationship { get; set; }
}

Case 2: Nested instance (composition)

The parent type of the property's type triggers a specific handling by the ORM, ensuring the instance is auto-created:

public class MyEntity : Entity
{
    // this is, in fact, an aggregation and is always initialized by the ORM, warning here
    [Field]
    public NestedPart SubPart { get; set; } // * the setter might be omitted
}

Currently available annotations:

One possibility is to annotate the whole property with a [NotNull] attribute. However, in that case the warning won't go away immediatelly, and it's necessary to delcare the property with a nullable reference type:

[Field]
[Association]
[NotNull]
public EntitySet<OtherEntity>? Relation { get; set; }

This is a partially acceptable solution, as both declaration-site warning is removed and when dereferencing the Relation property it won't cause a warning at use-site:

var x = something.Relation.Where(x => ...); // no warning here

However, using the ? at the same time a [NotNull] seems counter-intuitive.

Another option is to apply [NotNull] to the return of the getter. However, again the warning won't go away unless a nullable reference type is used:

[Field]
[Association]
public EntitySet<OtherEntity>? Relation { [return: NotNull] get; set; }

This mitigates the declaration-site warning, but the use-site warning remains:

var x = something.Relation.Where(x => ...); // warning here

The question is, whether there is a way to null-annotate such properties without using nullable reference types, or whether these scenarios are unsupported by the existing set of attributes and a ticket should be raised in the dotnet github repo?

Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
  • I find it surprising that `[NotNull] SomeType? SomeProperty { get; set; }` is "counterintuitive" to you. If anything, `[NotNull] SomeType SomeProperty { get; set; }` (what you seem to be proposing) is more counterintuitive: you are saying that a property, whose type is already non-nullable, is "not null". That just seems redundant. If the type were a nullable type on the other hand, the `[NotNull]` annotation clearly points out that although the property's _type_ is nullable, it is actually not null. – Sweeper Sep 12 '21 at 13:47
  • I don't know about the ORM that you are using, but does it actually generate code to initialise the properties _in the constructor_? If not, then there can be a time after the object has been instantiated when those properties are null, in which case the properties should definitely be nullable, and be marked with `[DisallowNull]` instead. – Sweeper Sep 12 '21 at 13:56
  • @Sweeper Yes, once the constructor is executed all such properties are initialized. The ORM injects the code using a Fody-based weaver, so the C# compiler has no chance to understand this. You are making a good point regarding the `[NotNull] SomeType` case — most likely, a new, better-named attribute would be necessary. – Ondrej Tucny Sep 12 '21 at 16:13

1 Answers1

1

I don't think there's any other way to annotate it to disable this warning. You can, however, simply disable this diagnostic for some files via editorconfig file:

[{**/Responses/*.cs,**/Requests/*.cs,**/Models**/*.cs}]
# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable.
dotnet_diagnostic.CS8618.severity = none
Dreamescaper
  • 175
  • 2
  • 5