Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is constructor the only way to initialize non-nullable properties in a class in C#?

I have switched to enable nullable in my project that uses C#8. Now I have the following class:

public class Request
{
    public string Type { get; set; }
    public string Username { get; set; }
    public string Key { get; set; }
}

Compiler of course complains that it cannot guarantee that these properties won't be null. I can't see any other way of ensuring this than adding a constructor that accepts non-nullable strings.

This seems fine for a small class, but if I have 20 properties, is this the only way to list them all in a constructor? Is it possible somehow to e.g. enforce it with the initializer:

var request = new Request { Type = "Not null", Username = "Not null" }; // Get an error here that Key is null

P.S. There is a good answer that suggests using iniatlizer for properties, but that does not always work e.g. for types like e.g. Type that one cannot just intialize to some random value

like image 991
Ilya Chernomordik Avatar asked Dec 30 '19 12:12

Ilya Chernomordik


People also ask

What is non nullable?

Nullable variables may either contain a valid value or they may not — in the latter case they are considered to be nil . Non-nullable variables must always contain a value and cannot be nil . In Oxygene (as in C# and Java), the default nullability of a variable is determined by its type.

What is a constructor C#?

Constructors are special methods in C# that are automatically called when an object of a class is created to initialize all the class data members. If there are no explicitly defined constructors in the class, the compiler creates a default constructor automatically.


2 Answers

Object initializer syntax is really just short-hand for explicitly assigning to fields or property setters, i.e.

var request = new Request { Type = "Not null", Username = "Not null" };

Is equivalent to:

var request = new Request();   // <-- All properties are default
request.Type = "Not null";     // <-- Type and key are default
request.Username = "Not null"; // <-- Key is still default

As you can see, the Request instance still goes through several states where the properties are in a default status, which will be null for reference types like string unless you assign a different default value in the constructor, as per the other answers.

Also, by specifying different default values

public string Type { get; set; } = ""
public string Username { get; set; } = "";
public string Key { get; set; } = "";

is equivalent to assigning these values in a default constructor, i.e.

public Request()
{
    Type = "";
    UserName = "";
    Key = "";
}

As you can imagine, this is a bit wasteful if you then immediately change the value again using object initializer syntax.

As an alternative, and if you don't require a mutable class, I would suggest instead that you provide one or more constructor overloads, which then supply suitable non-null default values for any missing fields, and then make the properties immutable e.g.

public class Request
{
    public Request(string type = "", string userName = "", string key = "")
    {
         Type = type;
         Username = userName;
         Key = key;
    }

    public string Type { get; }     // <-- No setter = immutable.
    public string Username { get; }
    public string Key { get; }
}

You can now instantiate the class without ever going through a state where any of the properties are ever null, and without the overhead of the intermediate default assignment, e.g.

var myRequest = new Request(key: "SomeKey"); // <-- Username and Type are defaulted to ""
like image 178
StuartLC Avatar answered Oct 10 '22 04:10

StuartLC


Initialise them in the definition

public string Type { get; set; } = ""
public string Username { get; set; } = "";
public string Key { get; set; } = "";

The object initializer syntax "new Request { }" is just syntactic sugar for new then assignment, so don't think you can get that to error in this case

like image 30
Milney Avatar answered Oct 10 '22 04:10

Milney