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 th
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);
}
}
}
Probably the most concise you can get is to use the null-coalescing operator:
get { return _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); }
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.
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;
}
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;
});
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>