Home > Blockchain >  C# how to mark the property of the abstract class is not null because setting is required in impleme
C# how to mark the property of the abstract class is not null because setting is required in impleme

Time:02-20

I have an abstract class as a base class for various implementations.

Let it look like this:

public abstract class MyBase {

    public object Property1 { get; protected set; }

}

It is important, that the type of Property1 is object and not object?. I want it to be completely clear that the Property1 is never null in implementation instance.

Let's say a typical implementation looks like this:

public sealed class MyImpl : MyBase {

    public MyImpl() {
        Property1 = new object();
    }

}

Of course in real world there are plenty of properties in the base class and they are of various types, not just object. I could mark the properties as abstract, but then I would have to implement them in each implementing class - that would mean more boilerplate code with no real benefit in that, right?

OK, but now I get a warning, that the properties must have non-null values before exiting constructor - CS8618. Of course I can disable the warning for my base class, but is there a more elegant way to instruct the compiler that the implementing class MUST set those properties to non-null values instead of disabling the warning?

It would be perfect if I get the warning not for the base class, but for the implementation if it doesn't set one of those properties.

As I already figured out - the latest C# compiler and Visual Studio has plenty of magic special attributes that change the nullable warning behavior, but I don't know where to look.

CodePudding user response:

It is important, that the type of Property1 is object and not object?. I want it to be completely clear that the Property1 is never null in implementation instance.

The only way to guarantee that is with a protected constructor in MyBase that requires a value for Property1 or by making Property1 an abstract property.

In .NET, when a subclass is instantiated, first its supertype's constructor runs to completion, and then the constructor of the next child type, and so on. There is currently no provision in .NET for a supertype to have a "post-constructor" that runs after the most-derived-type's constructor runs (I wish there was though..), so there is no way for MyBase class to prove to the compiler that Property1 will be in a valid state when the object is constructed. Having a protected set isn't any kind of provable guarantee (at least as far as the compiler is concerned): it's the OOP equivalent of a subclass saying "I pinkie-swear to set this property in my constructor!" and the rest of your program has to trust that verbal promise.

This is why the nullable annotations since C# 8.0 are so important and so useful: because now we no-longer need to operate on mere trust: we can now have the compiler actually verify that a field/auto-property is actually assigned to a non-null value, thus preventing any NullReferenceException (everyone's favourite kind of exception!) from ever being thrown in the first place.

The fact the non-abstract subclass is sealed doesn't matter to the compiler in this case because your MyBase could still be derived separately by a misbehaving subclass that never sets Property1.

Of course in real world there are plenty of properties in the base class and they are of various types, not just object. I could mark the properties as abstract, but then I would have to implement them in each implementing class - that would mean more boilerplate code with no real benefit in that, right?

I appreciate that having to copy paste or manually keystroke-in repetitive members is annoying, but doing so is not "boilerplate" if (re)implementing those abstract members is expressing something meaningful in your business/domain model.

I get a warning that the properties must have non-null values before exiting constructor - CS8618. Of course I can disable the warning for my base class, but is there a more elegant way to instruct the compiler that the implementing class MUST set those properties to non-null values instead of disabling the warning?

Just use a protected constructor. That's exactly what they're for.

Like this:

public abstract class MyBase
{
    protected MyBase(object property1Value)
    {
        this.Property1 = property1Value ?? throw new ArgumentNullException(nameof(property1Value));
    }

    public object Property1 { get; }

}

That way all subclasses will be safe:

public sealed class Derived : MyBase
{
    public Derived()
        : base( GetProperty1FromAStaticFactory() )
    {

    }
}

or

public sealed class Derived : MyBase
{
    public Derived( Object p1Value )
        : base( p1Value  )
    {

    }
}

CodePudding user response:

you are probably using net 6. Just comment or remove nullable option from a project properties. You will get rid of many problems and warnings

 <!--<Nullable>enable</Nullable>-->

Some of people thinks that it is usefull but I doubt since you can start to make nullable all properties of all your classes in the project manually.

so alternative

 public object? Property1 { get; protected set; }

that even looks very ridiculous, since a reference type is nullable in all another languages by default.

  • Related