2012-12-21 39 views
3

怎麼寫有這種形式的函數:如何在C#中編寫看起來像A(key,B(key,C(key,ValFactory(key))))的遞歸函數?

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。

緩存的工作方式是,如果第一級緩存沒有特定鍵的條目,它會嘗試查找第二級緩存。第2級緩存看起來未命中的3級緩存等

沒有任何緩存可以有另外一個緩存的任何知識,它應該只是執行簽名TResult GetOrAdd(string, Func<string, TResult> functionToCallOnCacheMiss)

+0

你一定要表現出一定的代碼。否則,它的頭腦閱讀。 – nawfal

回答

1

如果要存儲在每個Func鍵一個鏈表,爲什麼不直接遍歷這個列表並用前面的結果調用下一個func?

+0

這是從我想要的 - 我希望當前節點從列表中的下一個節點獲取它的值 – Arash

+2

因此,以相反的順序遍歷列表?我仍然對這是一個遞歸問題感到困惑?!這聽起來更像是你需要一個堆棧/隊列的功能。 –

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); 
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); 
+0

我會嘗試這種方法,看看它明天是否有效,現在是午夜。謝謝您的發佈! :) – Arash

+0

@Arash:它工作? –