Click here to Skip to main content
6,305,776 members and growing! (16,966 online)
Email Password   helpLost your password?
General Programming » Algorithms & Recipes » General     Intermediate License: The Code Project Open License (CPOL)

Local recursion with anonymous methods and simple Threading

By Mr.PoorEnglish

anonymous methods help keeping the "environment" of recursive processing encapsulated
C# (C# 3.0), .NET (.NET 2.0, .NET 3.0, .NET 3.5), Design
Posted:11 Jul 2008
Updated:4 Oct 2008
Views:8,421
Bookmarked:27 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
11 votes for this article.
Popularity: 4.81 Rating: 4.62 out of 5

1

2

3
4 votes, 36.4%
4
7 votes, 63.6%
5

Introduction

Recursive functions can get a little complex, when to deal with several vars. Either these vars must become class-member (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) => {
              Console.WriteLine(sDir);
              foreach (var S in System.IO.Directory.GetDirectories(sDir)) {
                 Recurse(S);
              }
           };
           Recurse(@"..\..");
        }

Thats 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)) {
                 Recurse(S);
              }
           };

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 to recommend)

Lets 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) => {
              Console.WriteLine(parent.FullName);
              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(DI); 
              }
           };
           Recurse(new DirectoryInfo(Root));
           Console.WriteLine(string.Concat(
              "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-ressources:

        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 issure 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)

Whats 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) MS insists on calling EndInvoke:

 Important Note: 
Always call EndInvoke to complete your asynchronous call. 

And EndInvoke() only can 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 there is 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. 

Conclusion  

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).

Ooooh!

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

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

License

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

About the Author

Mr.PoorEnglish


Member

Location: Germany Germany

Other popular Algorithms & Recipes articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 2 of 2 (Total in Forum: 2) (Refresh)FirstPrevNext
GeneralGood work PinmemberDonsw14:58 25 Jan '09  
GeneralGreat :) PinmemberBnaya Eshet4:19 7 Oct '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 4 Oct 2008
Editor: Chris Maunder
Copyright 2008 by Mr.PoorEnglish
Everything else Copyright © CodeProject, 1999-2009
Web11 | Advertise on the Code Project