2009-07-30 104 views
44

我有以下代码:C#中的匿名方法可以调用它自己吗?

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#中的匿名方法,使得它可以调用本身?

+0

从VS2008确切的抱怨是:局部变量“构建”可能不被初始化之前访问。 – Matt 2009-07-30 19:15:33

回答

78

你可以把它分解成两个语句,并使用捕获变量的魔法达到递归的效果:如果你要来的递归匿名方法的点

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

如果你正在创建一个递归函数,我建议避免匿名代表。只需创建一个方法并让它自己递归调用。

匿名方法的意思是匿名 - 你不应该通过名字(非匿名)来调用它们。

+3

+1我完全同意。 – 2009-07-30 19:19:01

+0

这个/自己仍然是匿名的。 – Lodewijk 2014-03-22 20:19:38

+0

递归函数比上面的命名委托更容易阅读。代表本身也需要定义,这也是该解决方案的负数,此外还有这个解决方案。 – TarmoPikaro 2016-03-16 10:31:49

10

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

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

递归是美丽的,lambda表达式是 最终抽象。但 他们怎么可以一起使用? Lambda是 匿名函数和递归 需要名称。

+0

+1为了说明错误存在的原因。解决问题的方法很简单(请参阅Mehrdad的答案),但首先我认为它不是一个好主意。 – 2009-07-30 19:20:07

1

,你可能希望促使它成为你班级中一种正常的,私人的方法。

23

Anonymous Recursion in C#在这个话题上有很好的讨论。

递归很漂亮,lambda是 的最终抽象。但 他们怎么可以一起使用? Lambda表达式是 匿名函数和递归 需要的名字......

由于这再次弹起,这里使用的Y组合子的例子:

// 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组合子,并成立了递归只委托,你没有得到CORRE ct递归。例如...

​​

但一切工作正常...

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组合子,它会如预期...

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

如果使用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); 
    } 
} 
相关问题