128

In C#,

Is there a way to turn an automatic property into a lazy loaded automatic property with a specified default value?

Essentially, I am trying to turn this...

private string _SomeVariable

public string SomeVariable
{
     get
     {
          if(_SomeVariable == null)
          {
             _SomeVariable = SomeClass.IOnlyWantToCallYouOnce();
          }

          return _SomeVariable;
     }
}

into something different, where I can specify the default and it handles the rest automatically...

[SetUsing(SomeClass.IOnlyWantToCallYouOnce())]
public string SomeVariable {get; private set;}
2
  • @Gabe: Note the class will only be called once if it never returns null. Commented Oct 27, 2010 at 19:25
  • I discovered that...it seems to be uses the singleton pattern Commented Oct 28, 2010 at 19:50

14 Answers 14

134

No there is not. Auto-implemented properties only function to implement the most basic of properties: backing field with getter and setter. It doesn't support this type of customization.

However you can use the 4.0 Lazy<T> type to create this pattern

private Lazy<string> _someVariable =new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce);
public string SomeVariable => _someVariable.Value;

This code will lazily calculate the value of _someVariable the first time the Value expression is called. It will only be calculated once and will cache the value for future uses of the Value property

Sign up to request clarification or add additional context in comments.

4 Comments

Actually, it looks to me like Lazy implements the singleton pattern. That is not my goal...my goal is create a lazy loaded property that is lazily instantiated but disposed along with the instance of the class in which it lives. Lazy does not seem to be performing that way.
@ctorx Lazy has nothing to do with the singleton pattern. It does exactly what you want it to do.
Note, SomeClass.IOnlyWantToCallYouOnce in your example must be static to be used with a field initializer.
Awesome answer. See my answer for a Visual Studio snippet you can use if you expect to have a many lazy properties.
47

Probably the most concise you can get is to use the null-coalescing operator:

get { return _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); }

4 Comments

In the case IOnlyWantToCallYouOnce returns null it will call it more than once.
When using the null-coalescing operator, the above example will fail. The correct syntax is: _SomeVariable ?? ( _SomeVariable = SomeClass.IOnlyWantToCallYouOnce() ); - notice the addition of the parenthesis around setting _SomeVariable if it is null.
This is the best option. First I used Lazy<>, but for our purposes this worked better. With latest C# it can also be written even more concise => _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); What some might not notice from the first look is that operator evaluates the right-hand operand and returns its result.
C# 8 lets you do public object MyProp => _myProp ??= new object();
30

Operator ??= is available using C# 8.0 and later, so you can now do it even more concise:

private string _someVariable;

public string SomeVariable => _someVariable ??= SomeClass.IOnlyWantToCallYouOnce();

Just be aware it's not thread-safe like the original version. With some overheads Lazy provides built-in safety if needed.

3 Comments

This is currently the best answer for C#8 and up.
Nice. Just be aware it's not thread-safe like the original version. With some overheads Lazy<T> provides built-in safety if needed.
It doesn't suit for properties of non-nullable types like struct or value.
21

There is a new feature in C#6 called Expression Bodied Auto-Properties, which allows you to write it a bit cleaner:

public class SomeClass
{ 
   private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce);

   public string SomeVariable 
   {
      get { return _someVariable.Value; }
   }
}

Can now be written as:

public class SomeClass
{
   private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce);

   public string SomeVariable => _someVariable.Value;
}

6 Comments

In the last section of code, the initialization is not actually lazy. IOnlyWantToCallYouOnce would be called during construction every time the class is instantiated.
So in otherwords this is not lazy loaded?
@Zapnologica My previous answer was a bit wrong but I updated it. SomeVariable is lazy loaded.
This answer reads more like a pitch for Expression Bodied Auto-Properties.
@AbleArcher Pointing out a new language feature is a pitch now?
|
7

Here's my implementation of a solve to your problem. Basically the idea is a property that will be set by a function at first access and subsequent accesses will yield the same return value as the first.

public class LazyProperty<T>
{
    bool _initialized = false;
    T _result;

    public T Value(Func<T> fn)
    {
        if (!_initialized)
        {
            _result = fn();
            _initialized = true;
        }
        return _result;
    }
 }

Then to use:

LazyProperty<Color> _eyeColor = new LazyProperty<Color>();
public Color EyeColor
{ 
    get 
    {
        return _eyeColor.Value(() => SomeCPUHungryMethod());
    } 
}

There is of course the overhead of passing the function pointer around, but it does the job for me and I don't notice too much overhead compared to running the method over and over again.

4 Comments

Wouldn't it make more sense to give the function to the constructor? This way you wouldn't be creating it inline each time, and you could dispose it after you used it the first time.
@lund.mikkel yeah, that would work too. May be use cases for both approaches.
If you pass the function to the constructor, much like .Net's Lazy class, then the function passed in will have to be static, I know this hasn't fit my design in many cases.
@MikkelR.Lund Sometimes you don't want to execute some code in the constructor but only on demand (and cache the result in form of a backing field)
6

Not like that, parameters for attributes must be constant in value, you cannot call code (Even static code).

You may however be able to implement something with PostSharp's Aspects.

Check them out:

PostSharp

Comments

4

I did it like this:

public static class LazyCachableGetter
{
    private static ConditionalWeakTable<object, IDictionary<string, object>> Instances = new ConditionalWeakTable<object, IDictionary<string, object>>();
    public static R LazyValue<T, R>(this T obj, Func<R> factory, [CallerMemberName] string prop = "")
    {
        R result = default(R);
        if (!ReferenceEquals(obj, null))
        {
            if (!Instances.TryGetValue(obj, out var cache))
            {
                cache = new ConcurrentDictionary<string, object>();
                Instances.Add(obj, cache);

            }


            if (!cache.TryGetValue(prop, out var cached))
            {
                cache[prop] = (result = factory());
            }
            else
            {
                result = (R)cached;
            }

        }
        return result;
    }
}

and later you can use it like

       public virtual bool SomeProperty => this.LazyValue(() =>
    {
        return true; 
    });

2 Comments

How do I use "this" at this context?
@Riera what do you mean? Just like regular property. E.g. public ISet<String> RegularProperty {get;set} public string CalculatedProperty => this.LazyValue(() => { return string.Join(",", RegularProperty.ToArray()); });
3

I'm a big fan of this idea, and would like to offer up the following C# snippet which I called proplazy.snippet.(you can either import this or paste it into the standard folder which you can get from the Snippet Manager)

Here's a sample of its output:

private Lazy<int> myProperty = new Lazy<int>(()=>1);
public int MyProperty { get { return myProperty.Value; } }

Here's the snippet file contents: (save as proplazy.snippet)

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>proplazy</Title>
            <Shortcut>proplazy</Shortcut>
            <Description>Code snippet for property and backing field</Description>
            <Author>Microsoft Corporation</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property type</ToolTip>
                    <Default>int</Default>
                </Literal>
                <Literal>
                    <ID>field</ID>
                    <ToolTip>The variable backing this property</ToolTip>
                    <Default>myVar</Default>
                </Literal>
                <Literal>
                    <ID>func</ID>
                    <ToolTip>The function providing the lazy value</ToolTip>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>

            </Declarations>
            <Code Language="csharp"><![CDATA[private Lazy<$type$> $field$ = new Lazy<$type$>($func$);
            public $type$ $property$ { get{ return $field$.Value; } }
            $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

1 Comment

I would set myProperty to be readonly, just to be safe
2

I don't think this is possible with pure C#. But you could do it using an IL rewriter like PostSharp. For example it allows you to add handlers before and after functions depending on attributes.

Comments

0

https://github.com/bcuff/AutoLazy uses Fody to give you something like this

public class MyClass
{
    // This would work as a method, e.g. GetSettings(), as well.
    [Lazy]
    public static Settings Settings
    {
        get
        {
            using (var fs = File.Open("settings.xml", FileMode.Open))
            {
                var serializer = new XmlSerializer(typeof(Settings));
                return (Settings)serializer.Deserialize(fs);
            }
        }
    }

    [Lazy]
    public static Settings GetSettingsFile(string fileName)
    {
        using (var fs = File.Open(fileName, FileMode.Open))
        {
            var serializer = new XmlSerializer(typeof(Settings));
            return (Settings)serializer.Deserialize(fs);
        }
    }
}

Comments

0

If you use a constructor during lazy initialization, following extensions may be helpful too

public static partial class New
{
    public static T Lazy<T>(ref T o) where T : class, new() => o ?? (o = new T());
    public static T Lazy<T>(ref T o, params object[] args) where T : class, new() =>
            o ?? (o = (T) Activator.CreateInstance(typeof(T), args));
}

Usage

    private Dictionary<string, object> _cache;

    public Dictionary<string, object> Cache => New.Lazy(ref _cache);

                    /* _cache ?? (_cache = new Dictionary<string, object>()); */

1 Comment

Is there an advantage to using your helper over LazyInitializer.EnsureInitialized()? Because from what I can tell, in addition to the functionality above, LazyInitializer provides error handling as well as sync functionality. LazyInitializer source code.
0
[Serializable]
public class ReportModel
{
    private readonly Func<ReportConfig> _getReportLayout;
    public ReportModel(Func<ReportConfig> getReportLayout)
    {
        _getReportLayout = getReportLayout;
    }

    private ReportConfig _getReportLayoutResult;
    public ReportConfig GetReportLayoutResult => _getReportLayoutResult ?? (_getReportLayoutResult = _getReportLayout());


    public string ReportSignatureName => GetReportLayoutResult.ReportSignatureName;
    public string ReportSignatureTitle => GetReportLayoutResult.ReportSignatureTitle;
    public byte[] ReportSignature => GetReportLayoutResult.ReportSignature;
}

1 Comment

While this might answer the authors question, it lacks some explaining words and links to documentation. Raw code snippets are not very helpful without some phrases around it. You may also find how to write a good answer very helpful. Please edit your answer.
0

Based on some answers here i made my own class for one-liner Lazy properties using c#5 CallerMemberName Attribute.

public class LazyContainer
{
    private Dictionary<string, object> _LazyObjects = new Dictionary<string, object>();
    public T Get<T>(Func<T> factory, [CallerMemberName] string name = null) where T: class
    {
        if (string.IsNullOrEmpty(name))
            return default(T);

        if (!_LazyObjects.ContainsKey(name))
            _LazyObjects.Add(name, new Lazy<T>(factory, true));

        return ((Lazy<T>)_LazyObjects[name]).Value;
    }
    public T Get<T>([CallerMemberName] string name = null) where T : class,new()
    {
        return Get(() => new T(), name);
    }
}

It can be used like this:

class PropertyClass
{
    private LazyContainer lc = new LazyContainer();

    public SimpleClass Prop1 => lc.Get<SimpleClass>();
    public LessSimpleClass Prop2 => lc.Get<LessSimpleClass>(()=> new LessSimpleClass(someParametrs...));
}

I added class constraint to restrict use to reference types, for value types i.e. int there is no point as it would return a copy anyway.

public int Prop3 => lc.Get<int>(()=>3);
//Would have the exact same function as this:
public int Prop4 => 3;

Comments

0

I'm surprised no one wrote this? Just initialize the property in the constructor.

    public Lazy<IUtil> Util { get; }

    public Foo()
    {
        this.Util = new Lazy<IUtil>(() => new Util());
    }

1 Comment

I think it was intended to have type string as public property and not Lazy<T>.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.