将委托序列的复杂交互链接在一起

发布于 2024-10-17 04:12:56 字数 1892 浏览 3 评论 0原文

这个问题问起来感觉相当复杂,虽然解决方案看起来很简单,但更多代表返回的代表内部的代表令人难以置信的程度导致我的大脑自行崩溃。

无需进一步说明,我将解释:

场景是您有翻译委托 (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)
            )
        );
}

这可行,但显然是这样;很没用。

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

提前致谢, 史蒂芬.

This feels quite complicated to ask, and whilst the solution seems simple, the shear mind bogglingness of delegates inside delegates returned from yet more delegates has caused my brain to implode in on itself.

Without further a do, I'll explain:

The scenario is that you have translation delegates (Func[A, B]) and translation behaviours (Func[A, Func[Func[A, B], B]]).

The idea is that around a given translation, you would have a specific set of behaviours that wrap the invocation to the translation, ie- that they take in the A, feel free to do with it what they wish, pass this on to the next behaviour, whilst being able to change the returning value (B).

There is probably some monad to describe this perfectly, but perhaps some code will help more than anything.

The victims:

public class B
{

}

public class A
{

}

The behaviour delegate

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

The function which should chain them together, and return a Func that allows a translation function to be passed in and get a new translation function which is wrapped by the behaviors

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

usage scenario

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

}

In the example code the behaviour implementations don't do anything put call the next behaviour, and our translation implementation simply returns a new B.

The function 'chain' is the problem function, being able to link the behaviours together has eluded me, but to prove to myself this should actually work, I hard coded a naive solution which specifically chains three behaviours together:

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

This works, but is obviously; quite useless.

Any help on this would be really useful, and any information on if this is a known pattern or monad would be really interesting, I don't think this code code is far from being generalizable.

Thanks in advance,
Stephen.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

倾城花音 2024-10-24 04:12:56

我没有完全理解你的场景 - 没有一些额外的上下文,它听起来太复杂了:-)但是,仅从类型来看,我认为你正在寻找的实现是这样的。诀窍是添加一个与 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;
}

您可以添加异常处理并处置枚举器,但这应该是正确的结构。

I didn't fully understand your scenario - without some additional context, it just sounds too complicated :-) However, just from the types, I think the implementation you're looking for is something like this. The trick is to add a method that works with IEnumerator and is recursive:

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

You could add exception handling and dispose the enumerator, but this should be the right structure.

月野兔 2024-10-24 04:12:56

这个想法是,围绕给定的翻译,您将拥有一组特定的行为,将调用包装到翻译中,即,他们接受 A,随意使用它做他们想做的事情,将其传递下去到下一个行为,同时能够更改返回值 (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 以及其他类似的类来传递它们。根据您想要的语法,您可能需要添加一些扩展方法来为这些包装器提供更流畅的编码样式。

The idea is that around a given translation, you would have a specific set of behaviours that wrap the invocation to the translation, ie- that they take in the A, feel free to do with it what they wish, pass this on to the next behaviour, whilst being able to change the returning value (B).

This sentence seems the clearest statement of your problem in the question. It sounds like you have

A -> {Black Box} -> B

and want

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

If that is all you want, I would recommend an interface and an implementation of that interface that wraps another implementation. This seems similar to the Composite or Proxy patterns, though it's not quite either one.

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

The nice thing here is that you can pass "nest" or "chain" TranslatorWrappers and other similar classes by passing them in the constructor parameters. Depending on the syntax you want, you may want to add some extension methods to provide a more fluid coding style for these wrappers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文