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」関数を実装するいくつかの異なるキャッシュがあります。第 1 レベルのキャッシュは、既に GetOrAdd 関数を持っている単なる ConcurrentDictionary です。

キャッシュの仕組みは、第 1 レベルのキャッシュに特定のキーのエントリがない場合、第 2 レベルのキャッシュを調べようとすることです。第 2 レベルのキャッシュは、ミスなどで第 3 レベルのキャッシュを参照します。

キャッシュは別のキャッシュの知識を持つべきではなく、署名を実装するだけですTResult GetOrAdd(string, Func<string, TResult> functionToCallOnCacheMiss)

4

3 に答える 3

1

各 Func をリンクされたリストに保存している場合は、リストを繰り返し処理して、前の結果で次の Func を呼び出してみませんか?

于 2012-12-21T02:07:38.353 に答える
0

その例を少し作りました。2 つの異なるデリゲートを使用する代わりに、単純化するために 1 つだけを使用します。パラメータとして渡された最後のメソッドがキューにアクセスしようとしないようにするのは、ユーザーの責任です。ただし、おそらく再配置できます。

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 に答える