C# 中的匿名方法可以调用自身吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1208703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can an anonymous method in C# call itself?
提问by Matt
I have the following code:
我有以下代码:
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;
};
......
}
}
Is there another way to set up an anonymous method in C# such that it can call itself?
有没有另一种方法可以在 C# 中设置一个匿名方法,以便它可以调用自己?
采纳答案by Mehrdad Afshari
You can break it down into two statements and use the magic of captured variables to achieve the recursion effect:
您可以将其分解为两个语句,并利用捕获变量的魔力来实现递归效果:
myDelegate build = null;
build = delegate(Object bj)
{
var letters= string.Empty;
if (someCondition)
return build(some_obj);
else string.Empty;
};
回答by Reed Copsey
If you're creating a recursive function, I'd recommend avoiding anonymous delegates. Just create a method and have it call itself recursively.
如果您要创建递归函数,我建议您避免使用匿名委托。只需创建一个方法并让它递归调用自己。
Anonymous methods are meant to be anonymous - you shouldn't be calling them by name (non-anonymously).
匿名方法是匿名的——你不应该按名字(非匿名)调用它们。
回答by Andrew Hare
You cannot call build
inside build
itself since the body of the anonymous method is the initialization of the variable itself. You are trying to use a variable before it is defined.
您不能build
在内部调用,build
因为匿名方法的主体是变量本身的初始化。您试图在定义变量之前使用它。
Not that I recommend this (as it would be muchsimpler to create a real method here that is recursive) but if you are interested you can read Anonymous Recursion in C#:
这并不是说我建议这个(因为这将是很多简单的在这里创建一个真正的方法是递归的),但如果你有兴趣,你可以阅读在C#匿名递归:
Recursion is beautiful and lambdas are the ultimate abstraction. But how can they be used together? Lambdas are anonymous functions and recursion requires names.
递归是美妙的,而 lambda 是终极的抽象。但是它们如何一起使用呢?Lambda 是匿名函数,递归需要名称。
回答by Will Eddins
If you're getting to the point of recursive anonymous methods, you may want to promote it to be a normal, private method in your class.
如果您已经到了递归匿名方法的地步,您可能希望将其提升为类中的普通私有方法。
回答by JP Alioto
Anonymous Recursion in C#has a terrific discussion on this topic.
Recursion is beautiful and lambdas are the ultimate abstraction. But how can they be used together? Lambdas are anonymous functions and recursion requires names...
递归是美妙的,而 lambda 是终极的抽象。但是它们如何一起使用呢?Lambda 是匿名函数,递归需要名称...
Since this popped up again, here's an example of using the Y-combinator:
由于这再次弹出,这是使用 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;
}
Here's a usage of it to call an anonymous, recursive function ...
这是调用匿名递归函数的用法......
Func<int,int> exp = Y<int,int>( e => x => ( x <=1 ) ? 1 : x * e( x - 1 ) );
Console.WriteLine( exp(5) );
You will note that if you do not use the Y-combinator and set up the recursion with just the delegate, you do not get correct recursion. For example ...
您会注意到,如果您不使用 Y 组合器并仅使用委托设置递归,您将无法获得正确的递归。例如 ...
// This is BAD. Do not do this!
Func<int,int> badRec = null;
badRec = x => ( x <= 1 ) ? 1 : x * badRec( x - 1 );
But everything works fine ...
但一切正常...
Console.WriteLine( badRec(5) );
// Output
// 120
But try this ...
但是试试这个...
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
What?!?
什么?!?
You see, after the line badRec = x => x + 1;
, the delegate you actually have is this ...
你看,在这行之后badRec = x => x + 1;
,你实际拥有的代表是这个......
badRecCopy = x => ( x <= 1 ) ? 1 : x * ( (x+1)-1 );
So, badRec is incrementing the value by 1 which we expect (4+1=5)
, but badRecCopy is now actually returning the square of the value (5*( (5+1)-1 )
which we almost certainly did not expect.
因此,badRec 将我们期望的值增加了 1 (4+1=5)
,但是 badRecCopy 现在实际上返回了(5*( (5+1)-1 )
我们几乎肯定没有预料到的值的平方。
If you use the Y-combinator, it will work as expected ...
如果您使用 Y 组合器,它将按预期工作......
Func<int,int> goodRec = Y<int,int>( exp => x => ( x <=1 ) ? 1 : x * exp( x - 1 ) );
Func<int,int> goodRecCopy = goodRec;
And you get what you expect.
你会得到你所期望的。
goodRec = x => x + 1;
Console.WriteLine( goodRec(4) );
Console.WriteLine( goodRecCopy(5) );
// Output
// 5
// 120
You can read more about the Y-combinator(PDF Link).
您可以阅读有关Y 组合器的更多信息(PDF 链接)。
回答by Jord?o
If you use Y, your function becomes a parameter to the function itself, so that you can call it recursively:
如果您使用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);
}
}