I was wandering if I could initialize a (reference type) property (when its value is null
) using a reference to this
keyword, but without using the constructor.
In some cases I do not want to use the constructor to initialize the property so, if no one accesses it, its value will not be created.
Furthermore, I don't like to separate the property declaration from it's initialization in the constructor, if possible.
A typical example is a Command declaration for MVVM pattern programming:
private Command FAddRecordCommand = null;
public Command AddRecordCommand
{
get
{
if (this.FAddRecordCommand == null)
{
this.FAddRecordCommand = new Command(this.AddRecordCommandExecute);
}
return this.FAddRecordCommand;
}
}
private async void AddRecordCommandExecute()
{
//do something
}
I don't like to write three times the name of the FAddRecordCommand
member...
I tried with Auto-implemented properties, but the this
keyword is not accessible in the initialization:
public Command AddRecordCommand { get; } = new Command(this.AddRecordCommandExecute);
The compiler throws the error: Keyword 'this' is not available in current context
Is there a way to use the one-line declaration like the Auto-Implemented property provides, but making access to this
?
CodePudding user response:
This can be done using the null-coalescing assignment operator:
private Command addRecordCommand = null;
public Command AddRecordCommand
=> addRecordCommand ??= new Command(AddRecordCommandExecute);
This assigns to addRecordCommand
only if it is null, then returns the value of that field.
CodePudding user response:
It seems that your are looking for lazy initialization which you can implement with a help of LazyInitializer
// Eager command creation
private Command AddRecordCommandExecute() {
//TODO: put the right creation and initialization code here
return new Command(this.AddRecordCommandExecute);
}
// Backing Field
private Command FAddRecordCommand;
// Lazy initialized property:
// AddRecordCommandExecute() will be run once
// on the first AddRecordCommand read
public Command AddRecordCommand => LazyInitializer
.EnsureInitialized(ref FAddRecordCommand, AddRecordCommandExecute);
CodePudding user response:
I figured out a way to reduce the lines of code, and the access to the private member, with this technique:
private Command FAddRecordCommand = null;
public Command AddRecordCommand => LazyInitializer.EnsureInitialized(ref this.FAddRecordCommand, () => new Command(this.AddRecordCommandExecute));
private async void AddRecordCommandExecute()
{
//do something
}
Here I used:
- a lambda expression
=>
to replace theget
function of the property - the
ref
keyword to pass a reference to theFAddRecordCommand
member to allow its value to be changed - a lambda function
() => new ???
to return the new value needed for initialization - the LazyInitializer.EnsureInitialized method to assign the initialization value (thanks to Dmitry Bychenko for the suggestion)
This way the this
keyword is available, the declaration requires only one line of code, and I access the private member only once.
passing the member as ref
allows its value to be changed, and the Func<TProp>
allows the new value to be created only when initial value is null
.
If you don't like lambda expressions for property declaration, you can still declare it in one line:
public Command AddRecordCommand { get { return LazyInitializer.EnsureInitialized(ref this.FAddRecordCommand, () => new Command(this.AddRecordCommandExecute)); } }