Click here to Skip to main content
13,352,280 members (68,243 online)
Click here to Skip to main content
Add your own
alternative version


35 bookmarked
Posted 11 Jul 2008

Local Recursion with Anonymous Methods and Simple Threading

, 4 Oct 2008
Rate this:
Please Sign up or sign in to vote.
Anonymous methods help in keeping the "environment" of recursive processing encapsulated


Recursive functions can get a little complex when dealing with several vars. Either these vars must become class-members (violating the rule of encapsulation) or they must be passed as parameters through all the recursive (self-)calls.

A local recursion can work on the local vars of the surrounding method.

Here We Go

private void toolStripButton1_Click(object sender, EventArgs e) {
   Action<string> Recurse = null;
   Recurse = (sDir) => {
      foreach (var S in System.IO.Directory.GetDirectories(sDir)) {

That's the basic one, just to show the principle: create an anonymous Action, then call it.
The only unusual feature is: you can't declare and initiate in one line.

Action<string> Recurse = (sDir) => {
    foreach (var S in System.IO.Directory.GetDirectories(sDir)) {

will not work, because "Recurse" is used, before it is defined.

(Maybe you can disable this compiler-error, I don't know whether that's recommended.)

Let's Use the Benefits of Local Recursion

private void GetDirInfo(string Root) {
   int dirCount = 0;
   int fileCount = 0;
   long sizeSum = 0;
   Action<DirectoryInfo> Recurse = null;
   Recurse = (parent) => {
      var fileInfos = parent.GetFiles();
      fileCount += fileInfos.Length;
      foreach (var FI in fileInfos) { 
         sizeSum += FI.Length; 
      var children = parent.GetDirectories();
      dirCount += children.Length;
      foreach (var DI in children) { 
   Recurse(new DirectoryInfo(Root));
      "dirCount: ", dirCount, "\tfileCount: ", 
      fileCount, "\tsizeSum: ", sizeSum));

This one collects information into 3 local vars. After that they can be displayed, without efforts.

Threading with Anonymous Methods

The other issue is, how to "transfer" a method-call into a side-thread. I use the Delegate.BeginInvoke() method, which takes threads from the threadpool. Other ways of threading may run faster, or may give more control on the side-thread-process - this approach is simple and is kind to system-resources:

private void toolStripButton2_Click(object sender, EventArgs e) {
   Action action = () => GetDirInfo(@"..\..");
   action.BeginInvoke(ar => action.EndInvoke(ar), null);

Yeah, this one is pretty short, isn't it? It translates the synchronous call to an asynchronous one.

Ähm..., and Now I'm Sorry...

... that issue can be made still more simple, without anonymous methods:

private void toolStripButton2_Click(object sender, EventArgs e) {
   Action<string> action = new Action<string>(GetDirInfo);
   action.BeginInvoke(@"..\..", action.EndInvoke, null);

(From here on, I've made some changes to this article.)

What's that strange BeginInvoke-Parameter (..., action.EndInvoke, ...)??

Look (with the objectbrowser) at Action.BeginInvoke()s Signature:

public virtual IAsyncResult BeginInvoke(System.AsyncCallback callback, object obj)

Browse on to see, what an "AsyncCallback" is - a delegate, defined as follows:

public delegate void AsyncCallback(System.IAsyncResult ar)

The BeginInvoke()-Pattern (please follow the link) wants us to implement a separate method with that signature, and pass the methods address to BeginInvoke(), for that the side-thread can call back, when its job is done. To that Callback-Method the side-thread will pass an IAsyncResult (whatever that may be).

Usually I don't need that. My threaded functions "know" themselves, when they run out. But (see the link above) Microsoft insists on calling EndInvoke:

<cite> Important Note: 
Always call EndInvoke to complete your asynchronous call.</cite> 

And EndInvoke() can only be called after the side-thread has run out (otherwise it blocks the main-thread, until the side-thread finishes).

Now watch the signature of Action.EndInvoke():

public virtual void EndInvoke(System.IAsyncResult result) 

Yeah, it is an AsyncCallback!
And for that Action.EndInvoke is a valid argument for Action.BeginInvoke().

One more param: (..., ..., null)??

(At this point, I have to say: I didn't design that.)
The last param of [Delegate].BeginInvoke() is to transfer data to the callback. That data will appear as "result.State" in the IAsyncResult, which is passed to the callback, when the side-thread calls back. As I said before: usually I don't need that.


Both issues can be assumed as a kind of "pattern": You can apply the recursion-stuff to mostly all recursive requirements.

Same to the threading-issue: It can translate any void method. (And I will take care to design my threading-stuff as void methods).


Now I've "finished" (is it possible to finish any programming-issue at all?) my article, trying hard to explain that threading-stuff. I stumbled over this: Competition-winner "C# Jun 2006"

Follow that link, to get a deep understanding about asynchronous calls in .NET-Framework.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Germany Germany
No Biography provided

You may also be interested in...


Comments and Discussions

Generaluh Pin
konikula6-Jan-10 21:29
memberkonikula6-Jan-10 21:29 
GeneralGood work Pin
Donsw25-Jan-09 14:58
memberDonsw25-Jan-09 14:58 
I like your recusion piece, good work
GeneralGreat :) Pin
Bnaya Eshet7-Oct-08 4:19
memberBnaya Eshet7-Oct-08 4:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.180111.1 | Last Updated 5 Oct 2008
Article Copyright 2008 by Mr.PoorEnglish
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid