ICYMI C# 9 New Features: Reduce Boilerplate Constructor Code with Init Only Prop...
source link: http://dontcodetired.com/blog/post/ICYMI-C-9-New-Features-Reduce-Boilerplate-Constructor-Code-with-Init-Only-Property-Setters
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
This is part of a series of articles on new features introduced in C# 9.
Prior to C# 9 if you wanted to create properties that can be set only when the object is created, you could make the property setter private and use constructor arguments to set them:
class
PaymentV1
{
public
Guid Id {
get
;
private
set
; }
public
decimal
Value {
get
;
private
set
; }
public
string
Notes {
get
;
set
; }
public
PaymentV1(Guid id,
decimal
value)
{
Id = id;
Value = value;
}
}
In the preceding code, the Id and Value properties can only be set when the object is created by supplying constructor parameters. Once the Payment has been created you can’t set the Id or Value properties from outside the object instance.
In the preceding code, we have to add the extra constructor code just to create the “externally immutable” properties (they can still be set from code inside the class).
C# 9 introduces the concept of init only setters. These allow you to create immutable properties without needing to write the extra constructor boilerplate code:
class
PaymentV2
{
public
Guid Id {
get
; init; }
public
decimal
Value {
get
; init; }
public
string
Notes {
get
;
set
; }
}
Notice in the preceding code that the Id and Value properties now use the init keyword instead of the set keyword. Also notice that we no longer need to create a constructor.
To set these immutable properties you need to do so at the time of object construction/creation by using the existing C# property initialization syntax, for example:
var
payment2 =
new
PaymentV2
{
Id = Guid.NewGuid(),
Value = 45.50m,
Notes =
"Initial send on Friday."
};
Once this code executes and the payment2 object is created, you will not be able to set Id or Value:
payment2.Id = Guid.NewGuid();
// ERROR - only settable in initializer
payment2.Value = 99.00m;
// ERROR - only settable in initializer
payment2.Notes +=
" Second send on Sunday."
;
// OK
You can also set init only properties from the constructor of a derived type:
abstract
class
PaymentBase
{
protected
Guid Id {
get
; init; }
protected
decimal
Value {
get
; init; }
}
class
PaymentV3 : PaymentBase
{
public
string
Notes {
get
;
set
; }
public
PaymentV3(Guid id,
decimal
value)
{
Id = id;
Value = value;
}
}
You could also use init only properties and set a default value if the property is not set at creation and also add validation logic:
class
PaymentV4
{
private
readonly
string
_currencyCode =
"USD"
;
public
string
CurrencyCode
{
get
{
return
_currencyCode;
}
init
{
if
(value
is
null
)
{
throw
new
ArgumentNullException(nameof(CurrencyCode));
}
if
(value.Length != 3)
{
throw
new
ArgumentOutOfRangeException(nameof(CurrencyCode),
"Must be 3 long."
);
}
// etc.
_currencyCode = value;
}
}
}
With the preceding code, we could try the follow statements:
var
payment4 =
new
PaymentV4();
// Default CurrencyCode of "USD"
var
payment4 =
new
PaymentV4 { CurrencyCode =
"AUD"
};
var
payment4 =
new
PaymentV4 { CurrencyCode =
null
};
// Exception
var
payment4 =
new
PaymentV4 { CurrencyCode =
"hello"
};
// Exception
If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.
SHARE:
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK