C # Lazy Loaded Automatic Properties

In C #,

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

Essentially, I'm trying to turn this on ...

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

into something else where I can specify a default value and it automatically processes the rest ...

 [SetUsing(SomeClass.IOnlyWantToCallYouOnce())] public string SomeVariable {get; private set;} 
+90
c #
Oct 27 '10 at 19:17
source share
11 answers

No, not there. Automatically implemented properties only function to implement the most basic properties: an auxiliary field with a getter and setter. It does not support this type of setup.

However, you can use type 4.0 Lazy<T> to create this template.

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

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

+102
Oct 27 '10 at 7:20
source share

Most likely, the most concise you can get is the use of the operator with zero coalescence:

 get { return _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); } 
+32
Oct 27 '10 at 19:23
source share

C # 6 has a new feature called Expression Bodied Auto-Properties that allows you to write this a little cleaner:

 public class SomeClass { private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); public string SomeVariable { get { return _someVariable.Value; } } } 

Now you can write as:

 public class SomeClass { private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); public string SomeVariable => _someVariable.Value; } 
+14
Jun 29 '16 at 7:57
source share

Not so, the parameters for the attributes must be constant in value; you cannot call code (even static code).

However, you can implement something using PostSharp Aspects.

Check them out:

Postsharp

+5
27 Oct '10 at 7:20
source share

Here is my implementation of the solution to your problem. In principle, an idea - this property, which will be set by the function at the first access and subsequent access, will give 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()); } } 

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

+5
Jun 26 '11 at 3:13
source share

I am a big fan of this idea and would like to suggest the following C # code snippet, which I called proplazy.snippet. (You can import it or paste it into a standard folder, which you can get from the Fragment Manager)

Here is an example of its output:

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

Here is the contents of the fragment file: (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> 
+3
Sep 18 '18 at 18:01
source share

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

+2
Oct 27 '10 at 19:19
source share

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 as

  public virtual bool SomeProperty => this.LazyValue(() => { return true; }); 
+1
Oct 24 '18 at 16:05
source share

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

 public class MyClass { // This would work as a method, eg 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); } } } 
0
Jun 22 '17 at 6:38
source share
 [Serializable] public class RaporImza { private readonly Func<ReportConfig> _getReportLayout; public RaporImza(Func<ReportConfig> getReportLayout) { _getReportLayout = getReportLayout; } private ReportConfig _getReportLayoutResult; public ReportConfig GetReportLayoutResult => _getReportLayoutResult ?? (_getReportLayoutResult = _getReportLayout()); public string ImzaAtanKisiAdi => GetReportLayoutResult.ReportSignatureName; public string ImzaAtanKisiUnvani => GetReportLayoutResult.ReportSignatureTitle; public byte[] Imza => GetReportLayoutResult.ReportSignature; } 

and i call as below

 result.RaporBilgisi = new ExchangeProgramPersonAllDataModel.RaporImza(() => _reportConfigService.GetReportLayout(documentTypeId)); 
0
Sep 12 '18 at 13:41
source share

If you use the constructor during deferred initialization, the following extensions may be useful to you.

 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

Usage
  private Dictionary<string, object> _cache; public Dictionary<string, object> Cache => New.Lazy(ref _cache); /* _cache ?? (_cache = new Dictionary<string, object>()); */ 
0
Oct 28 '18 at 3:02
source share



All Articles