2009-07-30 66 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); 
    } 
} 
相關問題