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

时间:2009-07-30 19:13:00

标签: 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;

                };
   ......
   }
}

是否有另一种方法可以在C#中设置匿名方法,以便它可以自行调用?

6 个答案:

答案 0 :(得分:89)

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

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

答案 1 :(得分:30)

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

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

答案 2 :(得分:24)

Anonymous Recursion in C#对此主题进行了极好的讨论。

  

递归是美丽的,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;
}

以下是用来调用匿名递归函数的用法......

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

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

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

但一切正常......

Console.WriteLine( badRec(5) );

// Output
// 120

但试试这个......

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

什么?!?

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

badRecCopy = x => ( x <= 1 ) ? 1 : x * ( (x+1)-1 );

因此,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;

你得到了你期望的东西。

goodRec = x => x + 1;

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

// Output
// 5
// 120

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

答案 3 :(得分:10)

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

不是我推荐这个(因为在这里创建一个递归的真实方法会更简单 更简单)但是如果你有兴趣可以阅读Anonymous Recursion in C#

  

递归是美丽的,lambdas是   最终的抽象。但是怎么可能   他们一起使用?兰巴达是   匿名函数和递归   需要名字。

答案 4 :(得分:3)

如果您使用Y,您的函数将成为函数本身的参数,以便您可以递归调用它:

class myClass {
  private delegate string myDelegate(Object bj);
  protected void method() {
    myDelegate build = delegate(Object obj) {
      // f is the function itself, which is passed into the function
      return Functional.Y<Object, string>(f => bj => { 
        var letters = string.Empty;
        if (someCondition)
          return f(some_obj); // use f
        else return string.Empty;

      })(obj);
    };
  }
}

public static class Functional {
  public delegate Func<A, R> Recursive<A, R>(Recursive<A, R> r);
  public static Func<A, R> Y<A, R>(Func<Func<A, R>, Func<A, R>> f) {
    Recursive<A, R> rec = r => a => f(r(r))(a);
    return rec(rec);
  }
}

答案 5 :(得分:1)

如果您已经达到了递归匿名方法的目的,您可能希望将其提升为您班级中的普通私有方法。

相关问题