Search code examples
c#ooppropertieslazy-initialization

Property initialization and 'this'


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?


Solution

  • 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)); } }