Search code examples
c#lazy-evaluationlazy-initialization

Lazily evaluated property syntax difference


Are there any differences between the following two approaches (property with backing field and property with default value) for a lazily evaluated property or are they equivalent?

// (1)
public static class Foo
{
    private static readonly Lazy<Foo> instance = new Lazy<Foo>();
    public static Foo Instance { get; } = instance.Value;
}

// (2)
public static class Foo
{
    public static Foo Instance { get; } = new Lazy<Foo>().Value;
}

What I want to achieve is that an instance of Foo is created only when accessing Foo.Instance, not before --- more so, when Foo.Instance is never accessed, no instance should be created ever.


Solution

  • Well, actually, no, they're not different.

    But, and this is just an assumption mind you, they're not working either, at least not the way I hope you intended them do.

    You see, this syntax:

    <property declaration> = <expression>;
    

    Declares an initializer for the property, which will be executed on construction of the owning type.

    So this:

    private static readonly Lazy<Foo> instance = new Lazy<Foo>();
    public static Foo Instance { get; } = instance.Value;
    

    is not lazy at all. It will declare and construct a Lazy<Foo> (although you're probably missing the getter delegate here as well even though this compiles), however when you declare the property you end up with the property evaluating the lazy object upon construction of the owning type and thus it becomes non-lazy.

    The second one has the exact same problem, you construct and immediately evaluate the lazy object so it becomes non-lazy.

    The correct way, and this can only be achieved in sort of the first syntax form, is to use the property without an initializer, either this:

    private static readonly Lazy<Foo> instance = new Lazy<Foo>();
    public static Foo Instance
    {
        get { return instance.Value; }
    }
    

    or this:

    private static readonly Lazy<Foo> instance = new Lazy<Foo>();
    public static Foo Instance
    {
        get => instance.Value;
    }
    

    or probably best, as this:

    private static readonly Lazy<Foo> instance = new Lazy<Foo>();
    public static Foo Instance => instance.Value;
    

    This will declare a getter body that doesn't execute until you actually read the property.


    TL;DR To sum it up, the two examples you gave are not different, but they're both (probably) wrong and you need to change the property declaration to fix it.