4

I have a property which getter should load its value only the first time. The second time it returns the loaded value without loading it again:

private Object _MemberValue;

public Object MemberValue
{
    get
    {
        if(_MemberValue == null)
        {
            _MemberValue = LoadMember();
        }

        return _MemberValue;
    }
}

In VB.NET there is the Static keyword. With it you don't have to declare a class wide member.

Public Property MemberValue as Object
    Get
        Static value as Object = Nothing

        If (value is Nothing) Then
            value = LoadMember()
        End If

        Return value
    End Get
End Property

In C# there isn't such a keyword.

Are there better C# implementations of this problem or other patterns?

djv
  • 15,168
  • 7
  • 48
  • 72
user11909
  • 1,235
  • 11
  • 27

2 Answers2

10

Are there better C# implementations of this problem or other patterns?

Probably not. You can use Lazy<T> as an replacement if you like, but basically it is the same as your first example. Using Static in VB.NET has some serious drawbacks, so I wouldn't use it either way.

If you prefer Lazy<T>, this is what I would use:

private Lazy<object> _MemberLazy = new Lazy<object>(LoadMember);

public object MemberValue
{
    get
    {
        return _MemberLazy.Value;
    }
}
Community
  • 1
  • 1
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
4

Your initial approach seems appropriate, I have never had reason to do something different. That said if your goal here is to avoid a class level field that could potentially be written to outside the getter, perhaps something like this would work. There are a number of other ReadOnly, WriteOnce, SetOnce implementations that would also work similarly.

ReadOnlyField.cs

public class ReadOnlyField<T>
{
    private bool _frozen;
    private T _value;

    public T Value
    {
        get { return _value; }
        set
        { 
            if (_frozen)
                throw new InvalidOperationException();

            _value = value;
        }
    }

    public void Freeze()
    {
        _frozen = true;
    }
}

YourObject.cs

public class YourObject
{
    private readonly ReadOnlyField<object> _someMember;

    public object MemberValue
    {
        get
        {
            if(_someMember.Value == null)
            {
                _someMember.Value = LoadMember();
                _someMember.Freeze();
            }

            return _someMember.Value;
        }
    }

    public YourObject()
    {
        _someMember = new ReadOnlyField<object>();
    }
}

It's not perfect. Unlike your VB.Net example; code outside of the getter could write to the field first, but at least you're protected from it being overwritten after Freeze is called.

Community
  • 1
  • 1
Derrick Moeller
  • 4,808
  • 2
  • 22
  • 48
  • 2
    I didn't vote but I would assume it's because it seems like you are duplicating what Lazy does, which started in .NET 4 – the_lotus Feb 24 '17 at 14:31
  • @the_lotus Lazy has its own limitations. The question is unclear and not realistic. Load could be a function of other variables and you could need to refresh from UI or other events.. –  Feb 24 '17 at 14:35