在C#中,我可以包装Func以缓存结果吗

在C#中,我可以包装Func以缓存结果吗,c#,func,C#,Func,我编写了返回计算整数序列的Func的代码。我希望以最优雅的方式缓存中间结果。当前我的代码如下所示: private static Func<int, long> A237585() { Func<int, long> A = null; Func<int, long> B = null; Func<int, long> C = null; A = CreateCachingFunc((n) => n == 0

我编写了返回计算整数序列的
Func
的代码。我希望以最优雅的方式缓存中间结果。当前我的代码如下所示:

private static Func<int, long> A237585() {
    Func<int, long> A = null;
    Func<int, long> B = null;
    Func<int, long> C = null;
    A = CreateCachingFunc((n) => n == 0 ? 0 : B(n-1));
    B = CreateCachingFunc((n) => C(n) + (n == 1 ? 1 : 0));
    C = CreateCachingFunc(CreateSumProductPartitionSelect(A, (n, k) => Choose(n + k - 1, k)));
    return A;
}

private static Func<int, long> CreateCachingFunc(Func<int, long> original)
{
    var cache = new List<long>();
    Func<int, long> cachedVersion = (n) =>
    {
        while (n >= cache.Count) cache.Add(original(cache.Count));
        return cache[n];
    };
    return cachedVersion;
}
private static Func<int, long> A237585() {
    CachedFunc<long> A = null;
    CachedFunc<long> B = null;
    CachedFunc<long> C = null;
    A = (n) => n == 0 ? 0 : B(n-1);
    B = (n) => C(n) + (n == 1 ? 1 : 0);
    C = CreateSumProductPartitionSelect(A, (n, k) => Choose(n + k - 1, k));
    return A;
}
private static Func A237585(){
Func A=null;
Func B=null;
Func C=null;
A=CreateCachingFunc((n)=>n==0?0:B(n-1));
B=CreateCachingFunc((n)=>C(n)+(n==1?1:0));
C=CreateCachingFunc(CreateSumProductPartitionSelect(A,(n,k)=>Choose(n+k-1,k));
返回A;
}
私有静态Func CreateCachingFunc(Func原始)
{
var cache=新列表();
Func cachedVersion=(n)=>
{
而(n>=cache.Count)cache.Add(original(cache.Count));
返回缓存[n];
};
返回cachedVersion;
}
我希望它看起来像这样:

private static Func<int, long> A237585() {
    Func<int, long> A = null;
    Func<int, long> B = null;
    Func<int, long> C = null;
    A = CreateCachingFunc((n) => n == 0 ? 0 : B(n-1));
    B = CreateCachingFunc((n) => C(n) + (n == 1 ? 1 : 0));
    C = CreateCachingFunc(CreateSumProductPartitionSelect(A, (n, k) => Choose(n + k - 1, k)));
    return A;
}

private static Func<int, long> CreateCachingFunc(Func<int, long> original)
{
    var cache = new List<long>();
    Func<int, long> cachedVersion = (n) =>
    {
        while (n >= cache.Count) cache.Add(original(cache.Count));
        return cache[n];
    };
    return cachedVersion;
}
private static Func<int, long> A237585() {
    CachedFunc<long> A = null;
    CachedFunc<long> B = null;
    CachedFunc<long> C = null;
    A = (n) => n == 0 ? 0 : B(n-1);
    B = (n) => C(n) + (n == 1 ? 1 : 0);
    C = CreateSumProductPartitionSelect(A, (n, k) => Choose(n + k - 1, k));
    return A;
}
private static Func A237585(){
CachedFunc A=null;
CachedFunc B=null;
CachedFunc C=null;
A=(n)=>n==0?0:B(n-1);
B=(n)=>C(n)+(n==1?1:0);
C=CreateSumProductPartitionSelect(A,(n,k)=>Choose(n+k-1,k));
返回A;
}

可能吗?如何编写CachedFunc以在返回时隐式地将CachedFunc转换回Func,并隐式地将匿名lambda转换(包装)为缓存版本?如果这是不可能的,那么包装我的函数的最好方式是什么?我希望顶层代码看起来尽可能简单。

首先让我们将使用lambda的现有备忘录实现转换为显式捕获类(这与C编译器在看到lambda时自动创建的几乎相同):

类CachedFunc
{
私有列表缓存;
私人Func原件;
私人电话(int n)
{
而(n>=cache.Count)cache.Add(original(cache.Count));
返回缓存[n];
}
公共静态函数创建(函数原始)
{
返回new CachedFunc(){cache=new List(),original=original}.Call;
}
}
现在,我们只需要添加隐式转换:

class CachedFunc<T>
{
     private List<T> cache;
     private Func<int, T> original;
     private T Call(int n) {
        while (n >= cache.Count) cache.Add(original(cache.Count));
        return cache[n];
     }

     public static implicit operator CachingFunc<T>(Func<int, T> original)
     {
         return new CachedFunc<T>() { cache = new List<T>(), original = original };
     }

     public static implicit operator Func<int, T>(CachingFunc<T> memo)
     {
         return memo.Call;
     }
}
类CachedFunc
{
私有列表缓存;
私人Func原件;
私人电话(int n){
而(n>=cache.Count)cache.Add(original(cache.Count));
返回缓存[n];
}
公共静态隐式运算符CachingFunc(Func-original)
{
返回new CachedFunc(){cache=new List(),original=original};
}
公共静态隐式运算符Func(CachingFunc memo)
{
回信备忘录。电话;
}
}

这是家庭作业吗?你的代码怎么了?你如何衡量“最优雅”和“尽我所能的简单”?这叫做记忆化。我正在寻找新的有趣的序列添加到OEIS中。这个是我的。总的来说,我希望有一段外观非常简单的代码作为主要描述,并带有到其余实现的链接。如果您不想为此推出自己的解决方案,那么有一些记忆库,比如MbCache();CachedFunc B=null;CachedFunc C=null;A=新函数((n)=>n==0?0:B(n-1));B=(n)=>C(n)+(n==1?1:0);C=CreateSumProductPartitionSelect(A,(n,k)=>Choose(n+k-1,k));返回A;分配A表示“B是一个变量,但像方法一样使用”。分配B表示“无法将lambda表达式转换为CachedFunc类型,因为它不是委托类型”。分配C很好。@Guy:不能在C#中使用户定义的对象可调用。但是使用
B.Call(n-1)
(当然要公开)。一个扩展方法可能有助于从lambdas分配这些对象。@Guy:BTW,如果您将名称
CreateCachingFunc
缩短为例如
memo