Skip to content

Nullable Reference Types: Child classes should be responsible for initializing fields not initialized by abstract parents #27015

Open

Description

Version Used: 05/14/18 Nullable Reference Types Preview (csc reports 2.8.0.62830 (e595ee27)) with Visual Studio 15.7.1

Demonstration Code:

public abstract class AbstractBaseClass
{
    public string Property0 { get; protected set; }
    public string Property1 { get; protected set; }
    public string Property2 { get; private set; }
    public string Property3 { get; protected set; }

    // warning CS8618: Non-nullable property 'Property0' is uninitialized.
    // warning CS8618: Non-nullable property 'Property1' is uninitialized.
    // warning CS8618: Non-nullable property 'Property2' is uninitialized.
    public AbstractBaseClass()
        => Property3 = "3";
}

public class ChildClass : AbstractBaseClass
{
    public string Property4 { get; private set; }

    // warning CS8618: Non-nullable property 'Property4' is uninitialized.
    public ChildClass()
        => Property0 = "0";
}

Expected Behavior:

The constructor for AbstractBaseClass has a warning for Property2 and no others.

The constructor for ChildClass has a warning for Property1 and Property4.

Actual Behavior:

(The warnings received are as displayed in the comments in the example code.)

The constructor for AbstractBaseClass has a warning for Property0, Property1, and Property2 despite ChildClass being capable of initializing Property0 and Property1.

The constructor for ChildClass only receives a warning for Property4


This is potentially non-trivial since the abstract class could lie within another assembly. I feel like the easiest solution would be to add an attribute [DefinitelyInitialized] to fields/properties that are appropriately initialized by the abstract constructors. However, I don't know how this would handle multiple constructors since you could initialize different subsets of properties in different constructors.

Some people might consider relying on child implementations to perform initialization to be evil, but I'd consider it to be in the same realm as the problem described on the wiki page with indirect initialization.

In our use-cases, creating the object needed by the base class is too complicated* to do before the base constructor is called, so we rely on child implementations assigning the property themselves.

(*In particular, we want to do some argument validation before constructing the object because it is a native resource and we don't want to leak its handle if we throw an exception after associating it with an IDisposable.)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions