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)
JP *_*oto 24
递归是美丽的,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链接).