Reputation: 5302
After a number of times I need to implement a Lazy<T>
pattern, it came to my mind the idea to put the whole pattern into a class in order to hide Lazy implementation.
In the case of "Loading a singleton configuration object for my services", I did something like this:
public interface IConfigurationProvider<T>
{
T GetConfiguration();
}
public abstract class SingletonConfigurationProvider<TConfiguration> : IConfigurationProvider<TConfiguration>
{
private static readonly Lazy<TConfiguration> _lazy =
new Lazy<TConfiguration>(_loadConfiguration);
private static Func<TConfiguration> _loadConfiguration;
private SingletonConfigurationProvider() { }
public SingletonConfigurationProvider(Func<TConfiguration> LoadConfig)
{
_loadConfiguration = LoadConfig;
}
public TConfiguration GetConfiguration()
{
return _lazy.Value;
}
}
My goal is to obtain, from the "outside" the simplicity in doing this:
public class ConfigTest : SingletonConfigurationProvider<ObjectTest>
{
public ConfigTest()
: base(Load)
{
}
public static ObjectTest Load()
{
return new ObjectTest()
{
testInt = 3,
testString = "Hi"
};
}
}
The points are:
_loadConfiguration
couldn't be null. Is it because the lazy is being constructed before the SingletonConfigurationProvider
constructor?Upvotes: 0
Views: 107
Reputation: 21480
The abstraction you're looking for is a memoising function. In this kind of function, you modify the getter function so that it implements an 'execute-it-only-once' kind of pattern. Untested code but roughly;
public Func<T> Memoize(Func<T> slowFunction) {
bool evaluated = false;
T value = default(T);
return () => {
if (!evaluated) {
value = slowFunction();
evaluated = true;
}
return value;
};
}
So you now have a function which you can use like this;
Func<TConfiguration> onceOnlyLoad = Memoise(Load);
Now you can call onceOnlyLoad()
as many times as you like and it'll only load the config first time you call it.
If you want, you can use Lazy<T>
internally to giv the same behaviour. Up to you.
Upvotes: 1