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.
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)
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.
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.
... 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)
(..., 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().
(..., ..., 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.
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 stumble over this: Competition-winner "C# Jun 2006"
Follow that link, to get a deep understanding about asynchronous calls in .Net-Framework.
| You must Sign In to use this message board. | |||||||||||
|
|||||||||||
|
|||||||||||
|
|||||||||||