Reputation: 2039
I'm testing c# 9.0 with NET 5.0 and there is something I don't understand. I enabled <nullable>enable</nullable>
.
If I write a class
public class Potato {
public string Colour { get; set; }
public string Flavour { get; set; }
}
I get the warning CS8618: Non-nullable propery 'Colour' must contain a non-null value when existing constructor. Consider declaring the propery as nullable.
I do NOT want to declare it nullable, that's why I enabled the tag...
Then, I declare the constructor:
public class Potato
{
public Potato(string colour, string flavour)
{
this.Colour = colour;
this.Flavour = flavour;
}
public string Colour { get; set; }
public string Flavour { get; set; }
}
So far so good. Now I want to create a Potato
object using the object initialiser:
var sweetPotato = new Potato {
Colour = "orange",
Flavour = "tasty",
};
And now I get the complain CS7036: There is no argument given that corresponds to the required formal parameter 'colour' of 'Potato.Potato(string, object)
. So, it tries to use the constructor I explicitly declared but I didn't introduce the parameters. I should do:
var sweetPotato = new Potato(
colour: "orange",
flavour: "tasty");
but here I am not using the object initialiser.
Another option would be declaring the class as
public class Potato
{
public string Colour { get; set; } = null!;
public string Flavour { get; set; } = null!;
}
with the null!
elements, but this allows some weird things like:
var sweetPotato = new Potato()
{
Colour = "orange",
};
which I think it is extremely weird. I declared 2 non nullable properties and thanks to the null!
I can load the object with one property but not loading the second one. That breaks my nullable tag!
Then my question is: is it possible to use the object initialiser with non nullable properties if the nullable tag is enabled?
If it is not, I think that for classes with non nullable properties, without any null!
involved, the default constructor should not be the empty one but the one with all arguments, and it should have to be possible to init an object with the object initialiser form, as long as all non-nullable properties are initialised.
Upvotes: 2
Views: 2032
Reputation: 1482
I know this is an old Question but here's the comprehensive answer:
<nullable>true<nullable>
tag you make it so that all nullables must be identified with ?
?
to their types, neither Colour
nor Flavour
can be NULL
Colour
and Flavour
- the default parameterless constructor won't work as it does nothing by itself and would return an object with NULL
in both Colour
and Flavour
, as that's the default for their types, which you requested the compiler not to allowThe snippet below:
var sweetPotato = new Potato {
Colour = "orange",
Flavour = "tasty",
};
uses the default parameterless constructor and so cannot be used. It is the shorthand equivalent to:
var sweetPotato = new Potato(); // sweetPotato has Colour and Flavour NULL
sweetPotato.Colour = "orange"; // sweetPotato still has Flavour NULL
sweetPotato.Flavour = "tasty";
which as you can see would create the object first (with default values) and assign values later. But by your not allowing the default value of NULL
, it fails
And this is why if you won't allow them to be nullable, you must add a constructor that initializes them, and you must use that constructor
This wouldn't apply if their types were of a primitive that has a different default - like an int
or a double
. In that situation, the default parameterless constructor would work. But by using types with a default value of NULL
, (like string
or any object
derived type), you can either make them nullable by adding ?
or you must use a constructor that initializes them to something other than NULL
.
Late, Late Edit You can use the object initializer still if you introduce a parameterless constructor that defaults those two properties:
public Potato()
{
Colour = "blue";
Flavor = "bitter";
}
Then you can do:
var bitterPotato = new Potato(); //blue and bitter potato
var sweetPotato = new Potato
{
Color = "orange",
Flavour = "tasty"
}; // orange and tasty potato
Upvotes: 2
Reputation: 9583
The default value for string
is null. As your property declarations do not define a default value, they will default to default
, which happens to be null
in the case of string
. The problem is that you have not declared the type as nullable
.
The solution is to assign a default value, such as String.Empty
:
public class Potato
{
public string Colour { get; set; } = String.Empty;
public string Flavour { get; set; } = String.Empty;
}
Upvotes: 1