Home > Enterprise >  Property initialization and 'this'
Property initialization and 'this'

Time:12-18

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 the get function of the property
  • the ref keyword to pass a reference to the FAddRecordCommand 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)); } }
  • Related