Here is an article on interview questions and answers on the init only setters in C# 9.
You will need to use an upgraded C# compiler for C# 9.0. Otherwise, the programs given here will not compile. Ques 1: What is the purpose of init
when get
-only and readonly
already exist?
The following explains the issues with the readonly and get-only setters. Then it explains how the init-only keyword solves them.
- Issues with
readonly
readonly
properties need additional and lengthy code for initialization. This code has to be provided through a constructor - which can be totally avoided by using theinit
keyword.- Issues with
get
-only get
only properties need a constructor to initialize them, which can make a class lengthy, and therefore diffcult to read.using System; class CMyClass { // get only public int mx { get; } // NOT possible to avoid a ctor public CMyClass(int x) { mx = x; } } class Program { static void Main(string[] args) { CMyClass cmc = new CMyClass(5); } }
- How
init
solves these issues? -
Now compare the following code with the
init
keyword. Notice how easier is it to write the class now. And also notice how convenient is it to use object initializer syntax now:using System; class CMyClass { // see how simple! // no ctor needed because of "init" public int mx { get; init; } } class Program { static void Main(string[] args) { // it is now possible to use // object initializer syntax // the initializer syntax is impossible // if "mx" were marked get only CMyClass cmc = new CMyClass() { mx = 7 }; // collection initialization // is easier, too CMyClass[] arr = { new CMyClass() { mx = 7 }, new CMyClass() { mx = 4 } }; } }
Ques 2: What is Construction Phase?
All the following are together called the Construction Phase:
- Situation 1: Constructor of a type
- The constructor function of a class, struct is referred as the Construction Phase.
- Situation 2: Constructor calls through
this, base
- In the following code we have two examples of the construction phase clearly marked as Examples 1 and 2:
using System; class CBase { // any property protected int mZ { get; init; } // any member int mX; // a parametric ctor public CBase(int x) { mX = x; } } class CMyClass : CBase { // Example 1: CONSTRUCTION PHASE // this(0) calls its own ctor public CMyClass() : this(0) { } // Example 2: CONSTRUCTION PHASE // base() calls its parent ctor public CMyClass(int x) : base(x) { } }
- Situation 3: Object Initializer
- We are in the construction phase when the object initializer code is running.
- Situation 4: Inside a
with
expression - The following program defines a record using the positional syntax. Then it creates a copy by altering the property
x
just in time. For details on positional syntax please refer my article (C# 9.0) Record types vs class vs struct type, positional records and non-destructive mutation. The construction phase is marked below.using System; // record defined with // positional syntax // yes! it is a one-liner public record RMyRecord(int x); class Program { static void Main(string[] args) { // create a record RMyRecord rec1 = new RMyRecord(9); // create a mutation using "with" // we are inside CONSTRUCTION PHASE here RMyRecord rec2 = rec1 with { x = 10 }; Console.WriteLine(rec1.ToString()); Console.WriteLine(rec2.ToString()); } }
- Situation 5: Inside an
init
- We are in contruction phase when an
init
accessor code is running. The init code could be running inside the derived class also, and could even be running in thebase
class also - effectively - everywhere.class CMyClass { // backing store int _mZ; public int mZ { get { return _mZ; } init { // we are inside Construction Phase _mZ = Math.Min(0, value); } } }
- Situation 6: Inside an Attribute
- The following code shows the Attribute class being used to set a property called
Name
. This, too, is an example of the construction phase.// inside CONSTRUCTION PHASE [MyAttribute(Name = "Hoven")] class CMyClass { }
Ques 3: What is the Importance of Construction Phase?
init
accessors can be set [i.e., executed] ONLY during a Construction Phase. After that they become get
only.
Ques 4: Explain how init
-only setters can be used to set base class properties?
As you can see in the code below, if the property X were marked as get
only, then a constructor would have been required. But if we use the init
keyword, then a constructor is not required, and the property X can be quickly set just-in-time of a derived class object, by using the object initializer syntax.
class CBase { // X would be in-accessible in derived // classes if the property X were marked // as public int X {get;} // we would have been forced to // add a ctor here public int X { get; init; } } class CDerived : CBase { } class Program { static void Main(string[] args) { // base class X being set CDerived cd = new CDerived() { X = 20 }; // better yet in C#9 // CDerived cd = new() { X = 20 }; } }
Ques 5: Compare the capabilities of init
and set
?
An init
setter can call other init
accessors and set the otherwise-allowed readonly
properties, but a set
cannot call other init
accessors, and neither can initialize any readonly
properties. The reason for this is that you are in the construction phase when inside an init
block, but you are NOT in the construction phase when inside a set
block.
Ques 6: Can a property be marked both as init
and readonly
?
No.
This Blog Post/Article "(C# 9.0 "init" setter) Six Interview Questions and Answers on the init Property Accessor" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.