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; }; ...... } }
有没有另外一种方法来build立一个匿名方法在C#中,以便它可以调用自己?
你可以把它分解成两个语句,并使用捕获variables的魔法来实现recursion效果:
myDelegate build = null; build = delegate(Object bj) { var letters= string.Empty; if (someCondition) return build(some_obj); else string.Empty; };
如果你正在创build一个recursion函数,我build议避免匿名代表。 只要创build一个方法,并让它自己recursion调用。
匿名方法的意思是匿名 – 你不应该通过名字(非匿名)来调用它们。
匿名recursion在C#中有关于这个话题的极好的讨论。
recursion是美丽的,lambda是最终的抽象。 但是他们怎么能一起使用呢? Lambdas是匿名函数,recursion需要名字…
由于这再次popup,这里是一个使用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; }
这是一个使用它来调用匿名,recursion函数…
Func<int,int> exp = Y<int,int>( e => x => ( x <=1 ) ? 1 : x * e( x - 1 ) ); Console.WriteLine( exp(5) );
你会注意到,如果你不使用Y-combinator并设置只有委托recursion,你不会得到正确的recursion。 例如 …
// 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是我们期望的(4+1=5)
将值递增1,但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链接)。
由于匿名方法的主体是variables本身的初始化,因此不能在build
内部调用build
。 您正在尝试在定义之前使用variables。
不是我推荐这个(因为在这里创build一个真正的方法是recursion的会更简单),但如果你有兴趣,你可以阅读匿名recursion在C#中 :
recursion是美丽的,lambda是最终的抽象。 但是他们怎么能一起使用呢? Lambdas是匿名函数,recursion需要名称。
如果你使用Y ,你的函数成为函数本身的一个参数,所以你可以recursion地调用它:
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); } }
如果您正在使用recursion匿名方法,您可能需要将其提升为class级中普通的私人方法。