如何编写具有此格式的函数:
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)
答案 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);