C#中的匿名方法可以自行调用吗?

Mat*_*att 53 c# recursion anonymous-methods

我有以下代码:

class myClass
{
private delegate string myDelegate(Object bj);

protected void method()
   {
   myDelegate build = delegate(Object bj)
                {
                    var letters= string.Empty;
                    if (someCondition)
                        return build(some_obj); //This line seems to choke the compiler
                    else string.Empty;

                };
   ......
   }
}
Run Code Online (Sandbox Code Playgroud)

有没有其他方法可以在C#中设置匿名方法,以便它可以调用自己?

Meh*_*ari 92

您可以将其分解为两个语句,并使用捕获的变量的魔力来实现递归效果:

myDelegate build = null;
build = delegate(Object bj)
        {
           var letters= string.Empty;
           if (someCondition)
               return build(some_obj);                            
           else string.Empty;
        };
Run Code Online (Sandbox Code Playgroud)

  • 确实;)但结果函数不是匿名的 - 在你的方法中,递归技巧*仍然*只能通过名称绑定. (13认同)

Ree*_*sey 30

如果您正在创建递归函数,我建议您避免使用匿名代理.只需创建一个方法并让它以递归方式调用自身.

匿名方法是匿名的 - 您不应该通过名称(非匿名)调用它们.


JP *_*oto 24

C#中的匿名递归对此主题进行了极好的讨论.

递归是美丽的,lambdas是最终的抽象.但它们如何一起使用呢?Lambdas是匿名函数,递归需要名称......

由于这再次出现,这是使用Y-combinator的一个例子:

// This is the combinator
public static Func<A,R> Y<A,R>( Func<Func<A,R>, Func<A,R>> f )
{
    Func<A,R> g = null;
    g = f( a => g(a) );
    return g;
}
Run Code Online (Sandbox Code Playgroud)

这是一个用来调用匿名递归函数的用法......

Func<int,int> exp = Y<int,int>( e => x => ( x <=1 ) ? 1 : x * e( x - 1 ) );
Console.WriteLine( exp(5) );
Run Code Online (Sandbox Code Playgroud)

您将注意到,如果您不使用Y-combinator并仅使用委托设置递归,则无法获得正确的递归.例如 ...

// This is BAD. Do not do this!
Func<int,int> badRec = null;
badRec = x => ( x <= 1 ) ? 1 : x * badRec( x - 1 );
Run Code Online (Sandbox Code Playgroud)

但一切正常......

Console.WriteLine( badRec(5) );

// Output
// 120
Run Code Online (Sandbox Code Playgroud)

但试试这个......

Func<int,int> badRec = null;
badRec = x => ( x <= 1 ) ? 1 : x * badRec( x - 1 );

Func<int,int> badRecCopy = badRec;

badRec = x => x + 1;

Console.WriteLine( badRec(4) );
Console.WriteLine( badRecCopy(5) );

// Output
// 5
// 25
Run Code Online (Sandbox Code Playgroud)

什么?!?

你看,在线之后badRec = x => x + 1;,你实际拥有的代表就是这个......

badRecCopy = x => ( x <= 1 ) ? 1 : x * ( (x+1)-1 );
Run Code Online (Sandbox Code Playgroud)

因此,badRec将值递增1,我们预期(4+1=5),但badRecCopy现在实际上返回了(5*( (5+1)-1 )我们几乎肯定没有预料到的值的平方.

如果您使用Y-combinator,它将按预期工作...

Func<int,int> goodRec = Y<int,int>( exp => x => ( x <=1 ) ? 1 : x * exp( x - 1 ) );
Func<int,int> goodRecCopy = goodRec;
Run Code Online (Sandbox Code Playgroud)

而你得到了你所期望的.

goodRec = x => x + 1;

Console.WriteLine( goodRec(4) );
Console.WriteLine( goodRecCopy(5) );

// Output
// 5
// 120
Run Code Online (Sandbox Code Playgroud)

您可以阅读有关Y-combinator的更多信息(PDF链接).

  • Y-combinator获胜!:-) (4认同)

And*_*are 10

你不能build在内部调用,build因为匿名方法的主体是变量本身的初始化.您正在尝试在定义之前使用变量.

不是我推荐这个(因为在这里创建一个递归的真实方法会简单)但是如果你感兴趣的话可以在C#中读取匿名递归:

递归是美丽的,lambdas是最终的抽象.但它们如何一起使用呢?Lambdas是匿名函数,递归需要名称.