在堆栈溢出这里我找到了记忆单参数函数的代码:
static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
var d = new Dictionary<A, R>();
return a=>
{
R r;
if (!d.TryGetValue(a, out r))
{
r = f(a);
d.Add(a, r);
}
return r;
};
}
Run Code Online (Sandbox Code Playgroud)
虽然这段代码对我来说很有用,但是当有多个线程同时调用memoized函数时,它有时会失败:Add使用相同的参数调用该方法两次并抛出异常.
如何使memoization线程安全?
我想为方法实现扩展方法.请考虑以下代码示例(http://dotnetfiddle.net/HztiOo):
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
A a = new A();
// Noticed that Next() is called twice
Console.WriteLine(a.Next(1));
Console.WriteLine(a.Next(1));
// Works
var withCache = ((Func<int,int>)a.Next).AddCaching();
withCache = new Func<int,int>(a.Next).AddCaching();
withCache = ExtensionMethods.AddCaching<int,int>(a.Next);
// Doesn't work :(
// withCache = a.Next.AddCaching<int,int>();
// Func<int,int> withCache = a.Next.AddCaching();
// Notice that Next() is only called once
Console.WriteLine(withCache(1));
Console.WriteLine(withCache(1));
}
}
public class A
{
public int Next(int n)
{
Console.WriteLine("Called Next("+n+")");
return …Run Code Online (Sandbox Code Playgroud) 我知道这个话题(记忆)已经讨论了很多(比如这里),但是我找不到任何满足我想要的 DRY 原则的答案,所以请阅读整个问题和我想要解决的三点.
我有一个像这样的简单支持类:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
没有什么特别花哨的,但它允许我这样做:
public …Run Code Online (Sandbox Code Playgroud)