Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Methods for Lazy Initialization with properties

I'm currently altering a widely used class to move as much of the expensive initialization from the class constructor into Lazy Initialized properties. Below is an example (in c#):

Before:

public class ClassA
{
    public readonly ClassB B;

    public void ClassA()
    {
        B = new ClassB();
    }
}

After:

public class ClassA
{
    private ClassB _b;

    public ClassB B
    {
        get
        {
            if (_b == null)
            {
                _b = new ClassB();
            }

            return _b;
        }
    }
}

There are a fair few more of these properties in the class I'm altering, and some are not used in certain contexts (hence the Laziness), but if they are used they're likely to be called repeatedly.

Unfortunately, the properties are often also used inside the class. This means there is a potential for the private variable (_b) to be used directly by a method without it being initialized.

Is there a way to make only the public property (B) available inside the class, or even an alternative method with the same initialized-when-needed?

This is reposted from Programmers (not subjective enough apparently): https://softwareengineering.stackexchange.com/questions/34270/best-methods-for-lazy-initialization-with-properties

like image 319
Stu Pegg Avatar asked Jan 06 '11 15:01

Stu Pegg


3 Answers

Well, my recommended solution would be to tell your coworker to use the property, not the field. But you could idiot-proof it to some degree like this:

public class ClassA
{
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB());

    public ClassB B
    {
        get
        {
            return _b.Value;
        }
    }
}

Now it's pretty hard to screw up.

like image 170
mqp Avatar answered Nov 02 '22 18:11

mqp


You could consider pushing the lazy properties into a base class to avoid direct access to the backing variable. Not ideal I know. I've always thought this was something lacking in C# i.e. direct support for lazy properties.

like image 6
Tim Lloyd Avatar answered Nov 02 '22 17:11

Tim Lloyd


@chibacity posted (and subsequently) deleted [and later undeleted :P] an alternative option using an abstract base class. While it may not be ideal in terms of code distribution it does provide a nice encapsulation removing a lot of code clutter making for a cleaner and more succinct ClassA. For instance, you could consider combining the techniques to achieve both goals:

public class ClassB { /* Class to be lazily instantiated */ }

public abstract class BaseA
{
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB());
    public virtual ClassB B { get { return _b.Value; } }
}

public class ClassA : BaseA
{
    public override ClassB B { get { return base.B; } }
}

At first glance, it seems like this is more long winded, but when you consider that ClassA which is the class you would be working in and with, this now means that all your references are going through the same property - there is no extraneous unnecessary field causing potential confusion, there's no bypassing the property to reference _b directly and there's no need to tell your coworker which to use... there's only one.

Not saying this is the right way to do this or that this is a pattern that should or shouldn't be followed, I'm just pointing out the advantages of what @chibacity suggested that may otherwise go unnoticed.

It would be nice if you could have implicit lazy loaded properties without having to refer to B.Value... for instance:

[Lazy]
public ClassB B { get; }

or for objects without parameterless constructors

[Lazy(() => new ClassB("Hello", "World"))]
public ClassB B { get; }

or perhaps as @chibacity suggested in a comment

public ClassB B { lazyget; }

or

public ClassB B { lazyget : new ClassB(); }

Alas, I don't think any of these are currently available solutions in any form...

like image 3
BenAlabaster Avatar answered Nov 02 '22 19:11

BenAlabaster