I know this topic (memoization) has been discussed quite a bit (like here), but no answer I could find satisfies the DRY principle as much as I would like, so please, read this whole question and the three points I want to address.
I have a simple support class like this:
public class Memoized<T1, TResult>
{
private readonly Func<T1, TResult> _f;
private readonly Dictionary<T1, TResult> _cache = new Dictionary<T1, TResult>();
public Memoized(Func<T1, TResult> f)
{
_f = f;
}
public TResult Invoke(T1 p1)
{
if (p1 == null) throw new ArgumentNullException(nameof(p1));
if (_cache.TryGetValue(p1, out var res)) return res;
return _cache[p1] = _f(p1);
}
public static Func<T1, TResult> Of(Func<T1, TResult> f)
{
var memo = new Memoized<T1, TResult>(f);
return x => memo.Invoke(x);
}
}
Nothing especially fancy, but it allows me to do this:
public class MyClass
{
public Func<int, bool> MemoizedMethod { get; }
private bool UncachedMethod(int v)
{
return v > 0;
}
public MyClass()
{
MemoizedMethod = Memoized<int, bool>.Of(UncachedMethod);
}
}
Now, even if the resulting code is not terribly noisy, I'm trying to figure out if the implementation could be more elegant, because currently I need:
- an invokable property that acts as a Method.
- a true method that should not be called directly.
- a line in the constructor (cannot be an inline initialization) that links the two (with a third repetition of the function signature!).
Any suggestion for a strategy that allows to remove one (or two!) of the above points would be great.