2

问这个问题感觉很复杂,虽然解决方案看起来很简单,但从更多代表返回的代表内部的代表令人难以置信的剪切思维导致我的大脑自爆。

不用多说,我将解释:

场景是您有翻译委托 (Func[A, B]) 和翻译行为 (Func[A, Func[Func[A, B], B]])。

这个想法是,围绕给定的翻译,您将有一组特定的行为,将调用包装到翻译中,即,他们接受 A,随意处理他们想要的,将其传递给下一个行为,同时能够更改返回值 (B)。

可能有一些 monad 可以完美地描述这一点,但也许一些代码会比任何东西都更有帮助。

受害者:

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。

函数“链”是问题函数,能够将行为链接在一起让我望而却步,但为了向我自己证明这应该有效,我硬编码了一个幼稚的解决方案,专门将三个行为链接在一起:

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)
            )
        );
}

这有效,但显然是;很没用。

对此的任何帮助都将非常有用,并且有关这是否是已知模式或 monad 的任何信息都将非常有趣,我认为此代码代码远非可推广。

在此先感谢斯蒂芬。

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

这个想法是,围绕给定的翻译,您将有一组特定的行为,将调用包装到翻译中,即,他们接受 A,随意处理他们想要的,将其传递给下一个行为,同时能够更改返回值 (B)。

这句话似乎最清楚地说明了您在问题中的问题。听起来你有

A -> {Black Box} -> B

并且想要

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

如果这就是你想要的,我会推荐一个接口和一个包含另一个实现的接口的实现。这似乎类似于 Composite 或 Proxy 模式,尽管两者都不完全一样。

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 回答