如何在C#中编写一个看起来像A的递归函数(key,B(key,C(key,ValFactory(key))))?

时间:2012-12-21 01:51:46

标签: c# function recursion functional-programming

如何编写具有此格式的函数:

A(key, B(key, C(key, ValFactory(key))))

A,B和C有这个签名的地方:

TResult GetOrAdd(string key, Func<string, TResult> generator);

而Valfactory有签名:

TResult Get(string key);

“链式”函数的数量没有限制btw,因此它可以是A,B或A,B,C或A,B,C,D,E等。

我将函数A,B,C等存储在LinkedList

我如何以我想要的方式打电话给他们?

编辑添加一些信息以便澄清:

我需要这个来实现多级缓存。有几个不同的缓存都实现了“GetOrAdd”功能。第一级缓存只是一个已经具有GetOrAdd函数的ConcurrentDictionary。

缓存的工作方式是,如果第一级缓存没有特定密钥的条目,它会尝试查找第二级缓存。第二级缓存查找未命中等级的第三级缓存

没有缓存应该知道另一个缓存,它应该只实现签名TResult GetOrAdd(string, Func<string, TResult> functionToCallOnCacheMiss)

3 个答案:

答案 0 :(得分:1)

如果您将每个Func存储在链接列表中,为什么不直接遍历列表并使用之前的结果调用下一个func?

答案 1 :(得分:0)

我为它做了一个小例子。它不使用两个不同的委托,而只使用一个来简化事情。用户有责任确保作为参数传递的最后一个方法不会尝试访问队列。不过,它可能会被重新安排。

public delegate TResult GetOrAdd<TResult>(string key, Queue<GetOrAdd<TResult>> generatorChain);

static T ExecuteChain<T>(string key, params GetOrAdd<T>[] generators)
{
    var queue = new Queue<GetOrAdd<T>>(generators.Skip(1));
    return generators.First()(key, queue);
}

static int A(string key, Queue<GetOrAdd<int>> generatorChain)
{
    var newKey = key.ToUpper();
    //You can perform checks on the queue
    //i.e. if it's empty, throw an exception
    var tempResult = generatorChain.Dequeue()(newKey, generatorChain);
    return tempResult*2;
}

static int B(string key, Queue<GetOrAdd<int>> generatorChain)
{
    var newKey = key.Insert(0, "My string is: ");
    var tempResult = generatorChain.Dequeue()(newKey, generatorChain);
    return tempResult + 1;
}

static int ValFactory(string key, Queue<GetOrAdd<int>> generatorChain)
{
    //Instead of defining another delegate, we just don't use the queue
    //You can still run your checks (i.e. throw exception if not empty)
    return key.GetHashCode();
}

你可以通过以下方式致电链:

var result = ExecuteChain<int>("Hello world", A, B, ValFactory);

答案 2 :(得分:0)

鉴于这些定义:

public delegate TResult GetOrAdd<TResult>(string key, Func<string, TResult> generator);
public delegate TResult Get<TResult>(string key);

你需要这样的功能:

public static Func<string, TResult> Chain<TResult>(Get<TResult> last, params GetOrAdd<TResult>[] funcs) {
    if (funcs.Count() == 0) return key => last(key);
    var head = funcs.First();
    var tail = funcs.Skip(1).ToArray();
    return key => head(key, Chain(last, tail));
}

编写如下代码:

var result = Chain(ValFactory, A, B, C)(key);

请注意,这看起来像chain of responsibility的类型。

更新:您还可以简化Chain并让客户端使用适配器函数使用所需的参数排序:

public static GetOrAdd<TResult> Adapt<TResult>(Get<TResult> factory) {
    return (key, next) => factory(key);
}

public static Func<string, TResult> Chain<TResult>(params GetOrAdd<TResult>[] funcs) {
    if (funcs.Count() == 0) return null; // or return key => default(TResult);
    var head = funcs.First();
    var tail = funcs.Skip(1).ToArray();
    return key => head(key, Chain(tail));
}

...

var result = Chain(A, B, C, Adapt(ValFactory))(key);