3

如何编写具有这种形式的函数:

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

其中 A、B 和 C 具有此签名:

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

Valfactory 有签名:

TResult Get(string key);

顺便说一句,“链接”函数的数量没有限制,因此它可以是 A、B 或 A、B、C 或 A、B、C、D、E 等。

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

我如何以我想要的方式称呼他们?

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

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

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

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

4

3 回答 3

1

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

于 2012-12-21T02:07:38.353 回答
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);
于 2012-12-21T02:58:41.843 回答
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通过适配器函数简化并让客户端使用所需的参数排序:

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);
于 2012-12-21T03:40:33.120 回答