There are a lot of numerical properties to be invoked many times with an expensive calculation. Let’s say for the sake of example, they expose a Factorial:
public class Analysis
{
public double n10 => F(10);
public double n100 => F(100);
double F(int n) =>
n <= 1 ? 1 : n * F(n-1);
}
I was looking for a way to cache them while keeping syntax clean, so property calculation logic will not intermix with caching. A proposed solution is:
public class Analysis
{
public double n10 => this.Cached() || F(10);
public double n100 => this.Cached() || F(100);
double F(int n) =>
n <= 1 ? 1 : n * F(n-1);
}
Where library code is:
public static class Caching
{
static ConditionalWeakTable<object, Dictionary<string, double>> Values { get; } =
new ConditionalWeakTable<object, Dictionary<string, double>>();
public static Value Cached(this object target, [CallerMemberName] string name = null) =>
Values.GetOrCreateValue(target).ContainsKey(name) ?
new Value(() => Values.GetOrCreateValue(target)[name], null) :
new Value(null, v => Values.GetOrCreateValue(target)[name] = v);
}
And:
public class Value
{
public static implicit operator Value(double value) => new Value(() => value, null);
public static implicit operator double(Value value) => value.Getter();
public static bool operator true(Value value) => value.Getter != null;
public static bool operator false(Value value) => value.Getter == null;
public static Value operator |(Value cached, Value computed)
{
cached.Setter(computed);
return computed;
}
public Value(Func<double> getter, Action<double> setter)
{
Getter = getter;
Setter = setter;
}
Func<double> Getter { get; }
Action<double> Setter { get; }
}
cached or calculated
. Unfortunately,??
is not overloadable. \$\endgroup\$