2

これを尋ねるのは非常に複雑に感じます。解決策は簡単に思えますが、さらに多くのデリゲートから返されたデリゲート内のデリゲートのせん断的な気が遠くなるほど、私の脳はそれ自体で内破しました。

これ以上何もせずに、私は説明します:

シナリオは、翻訳デリゲート (Func[A, B]) と翻訳動作 (Func[A, Func[Func[A, B], B]]) があることです。

アイデアは、特定の翻訳の周りに、呼び出しを翻訳にラップする特定の一連の動作を持つことです。戻り値を変更することができます (B)。

これを完全に説明するモナドはおそらくいくつかありますが、おそらくいくつかのコードが何よりも役立ちます。

被害者:

public class B
{

}

public class A
{

}

動作デリゲート

public delegate Func<Func<A, B>, B> TranslationBehavior(A input);

それらを連鎖させ、変換関数を渡すことができる Func を返し、動作によってラップされる新しい変換関数を取得する関数

static Func<Func<A, B>, Func<A, B>> Chain(IEnumerable<TranslationBehavior> behaviors)
{
    throw new NotImplementedException();
}

使用シナリオ

static void Main(string[] args)
{
    var behaviors = new[]
    {
        (TranslationBehavior) (inp => next => next(inp)),
        (TranslationBehavior) (inp => next => next(inp)),
        (TranslationBehavior) (inp => next => next(inp)),
    };

    var input = new A();

    var chained = Chain(behaviors);

    var output = chained(a => new B());

}

コード例では、動作の実装は何もせず、次の動作を呼び出します。変換の実装は単に新しい B を返します。

関数「チェーン」は問題の関数であり、動作を一緒にリンクできるかどうかはわかりませんでしたが、これが実際に機能することを証明するために、3 つの動作を具体的にチェーンする単純なソリューションをハードコーディングしました。

static Func<Func<A, B>, Func<A, B>> Chain(IEnumerable<TranslationBehavior> behaviors)
{
    var behavior1 = (TranslationBehavior)null;
    var behavior2 = (TranslationBehavior)null;
    var behavior3 = (TranslationBehavior)null;

    return translation => input =>
        behavior1(input)(transformed1 =>
            behavior2(transformed1)(transformed2 =>
                behavior3(transformed2)(translation)
            )
        );
}

これは機能しますが、明らかに機能します。かなり役に立たない。

これに関するヘルプは本当に役に立ちます。これが既知のパターンまたはモナドであるかどうかに関する情報は非常に興味深いものです。このコードコードは一般化できるとは思えません。

前もってありがとう、スティーブン。

4

2 に答える 2

3

私はあなたのシナリオを完全には理解していませんでした-いくつかの追加のコンテキストがなければ、複雑すぎるように聞こえます:-)しかし、タイプだけから、あなたが探している実装はこのようなものだと思います. トリックは、IEnumerator再帰的で動作するメソッドを追加することです:

Func<Func<A, B>, Func<A, B>> Chain
  (IEnumerable<TranslationBehavior> behaviors, Func<A, B> final) {
    return translation => Chain(behaviors.GetEnumerator(), translation);
}

// Recursive method that takes IEnumerator and processes one element..
Func<A, B> Chain
  (IEnumerator<TranslationBehavior> behaviors, Func<A, B> last) {
    if (behaviors.MoveNext())
      return input => behaviors.Current(input)(Chain(behaviors, last));
    else
      return last;
}

例外処理を追加して列挙子を破棄することもできますが、これは正しい構造である必要があります。

于 2011-02-13T00:16:04.837 に答える
1

アイデアは、特定の翻訳の周りに、翻訳への呼び出しをラップする特定の一連の動作があるということです。戻り値を変更することができます (B)。

この文は、質問での問題の最も明確なステートメントのようです。それはあなたが持っているように聞こえます

A -> {Black Box} -> B

そして欲しい

A -> pre-process A -> {same Black Box} -> B -> post-process and return B

それだけでよければ、インターフェースと、別の実装をラップするそのインターフェースの実装をお勧めします。これは、複合パターンまたはプロキシ パターンに似ているように見えますが、どちらとも言えません。

interface ITranslator 
{
    B Transform(A input);
}
class TranslatorWrapper : ITranslator
{
    TranslatorWrapper(ITranslator wrapped)
    {
        _wrapped = wrapped;
    }

    ITranslator _wrapped;

    B Transform(A input)
    {
        //do preprocessing here
        B result = _wrapped.Transform(input);
        //do postprocessing here
        return result;
    }
}

ここでの良い点は、「ネスト」または「チェーン」TranslatorWrappersおよび他の同様のクラスをコンストラクターパラメーターで渡すことで渡すことができることです。必要な構文によっては、いくつかの拡張メソッドを追加して、これらのラッパーにより流動的なコーディング スタイルを提供することができます。

于 2011-02-13T00:37:04.243 に答える