Here's a non-orthodox but quite effective technique I sometimes use to detect and avoid recursive calls to a method. You typically detect recursive calls by defining a boolean class-level field and testing it on entry to a method. This technique is often used in event handlers, for example in TextChanged handlers that modify the Text property of a control and that would therefore trigger an endless recursion:
Dim insideTextChanged As Boolean
Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged ' Exit if this is a recursive call. If insideTextChanged Then Exit Sub ' Forbid recursive calls from now on. insideTextChanged = True ' ... TextBox1.Text = TextBox1.Text & " " ' Permit recursive calls. insideTextChanged = FalseEnd Sub
This approach works well, but it requires a lot of code and forces you to define a distinct boolean field for each event handler. If you have many handlers, it quickly becomes a nuisance. In addition, if there is any chance that the method throws an exception, you must wrap all the code in a try block,so that you can reset the insideTextChanged to false in the finally section. Wouldn't it great if you could use a method that allows you to test if you are inside a recursive call? I am thinking of something like this:
Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged ' Exit if this is a recursive call. If IsRecursive() Then Exit Sub ' ... TextBox1.Text = TextBox1.Text & " "End Sub
Here's how you can implement the IsRecursive method:
<System.Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)> _Public Shared Function IsRecursive() As Boolean Dim st As New StackTrace ' Check whether any method in the call stack is the same as the immediate caller. For n As Integer = 2 To st.FrameCount - 1 If st.GetFrame(1).GetMethod() Is st.GetFrame(n).GetMethod() Then Return True Next Return FalseEnd Function
Here's the C# version:
[System.Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)]public static bool IsRecursive() { StackTrace st = new StackTrace(); // Check whether any method in the call stack is the same as the immediate caller. for ( int n= 2; n < st.FrameCount; n++ ) { if ( st.GetFrame(1).GetMethod() == st.GetFrame(n).GetMethod() ) return true; } return false;}
The IsRecursive method compares the immediate caller - that is, st.GetFrame(1).GetMethod() - with all the other methods on the call stack and returns True if it finds a match. It is essential that the IsRecursive method is decorated with the MethodImpl attribute, to ensure that the JIT compiler inlines it in its caller's body. In .NET 1.1 this should never happen, because the JIT compiler never inlines methods that contain loops, but I haven't checked under .NET 2.0 and obviously I can't make promises about future versions, therefore this attribute is your best defence.
Remember Me
Powered by: newtelligence dasBlog 1.8.5223.1