Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Friday, August 20, 2010

The evil debugger



Let's take a look at the following piece of C# code:





1:  using System; 
2:  using System.Collections.Generic; 
3:  using System.Linq; 
4:  using System.Text; 

5:  namespace ConsoleApplication1 { 
6:    class Program { 
7:      private string myString = null; 
8:      public string MyString { 
9:        get { 
10:          if (myString == null) { 
11:            myString = "Bad string"; 
12:          } 
13:          return myString; 
14:        } 
15:        set { 
16:          if (myString == null) { 
17:            myString = value; 
18:          } 
19:        } 
20:      } 
21:      public override string ToString() { 
22:        return MyString; 
23:      } 
24:      static void Main(string[] args) { 
25:        Program program = new Program(); 
26:        program.MyString = "Good string"; 
27:        Console.WriteLine(program); 
28:      } 
29:    } 
30:  }  


The result, as you would expect should be "Good string" written to the console. That is, when you run it from the command line.
Suppose I run it in Visual Studio .NET 2008 and I put a breakpoint at line 27 in the debugger. Then I debug the program, I reach line 27, I move to line 28 and the result is of course "Good string".
Let's put a breakpoint at line 26. You'd say "what does the breakpoint have to do with the result ?" Well, it does, because in this case, "Bad string" will be displayed. This is like Heisenberg principle (or the observer effect), isn't it ? When we debug, we actually influence the result. This is possible because when the breakpoint is set at line 26, MyString getter is executed and in effect myString is set to "Bad string". After that trying to set myString to "Good string" can't succeed because in the setter the test (myString == null) is false. At line 27 ToString() is called, displaying of course "Bad string".

The default behavior of the debugger in Visual Studio .NET 2008 is to evaluate the properties when the debugger hits them. Also, the ToString() method is called by default whenever you hover with the mouse pointer over an instance (like "program" in line 26).
You can disable these behaviors under Tools -> Options -> Debugging -> General.

It's good to know this, because as you can see, .NET properties and ToString() evaluation in VS.NET can give you lots of headaches.


Sunday, June 27, 2010

Invoke code on a certain thread in C# / .NET

Virtually all GUI frameworks and the languages that come with them give you the possibility to invoke a certain piece of code on the UI thread. This is necessary because the UI components aren't usually thread safe (making all their methods thread safe would be a big blow to the performance of the application), so any update of the UI can't be done from another thread. That piece of code needs to be marshalled to the main thread.
.NET goes a step further and offers us the possibility to invoke a piece of code on any thread. The example bellow shows how this can be done.
ThreadTask will be run in a new thread, whose name is "Alpha thread". We create a Control on this thread (new Control()) and then we create its handle: ctrl.CreateControl().
Finally, we do Application.Run(), which makes our thread wait for messages in the message loop.
Then we use our control to invoke the method MyTestMethod on our thread.

Note that control handle creation is essential; without it, MyTestMethod would be invoked on the main thread. Also, attaching the thread to the message loop by doing Application.Run() ensures that the thread waits for invokes from other threads.



using System;
using System.Windows.Forms;
using System.Threading;

namespace TestThreads2 {
    public class TestThread {
        private Control ctrl = null;

        // This method that will be called when the thread
        // is started
        public void ThreadTask() {
            if (ctrl == null) {
                // create the control
                ctrl = new Control();
                // create the handle
                ctrl.CreateControl();
            }
            Console.WriteLine("ThreadTask is running on thread: " +
                Thread.CurrentThread.Name);
            // ensure the message loop is attached to this thread
            Application.Run();
        }

        public Control Ctrl {
            get { return ctrl; }
            set { ctrl = value; }
        }
    }

    public class Program {
        private static void MyTestMethod() {
            Console.WriteLine("TestMethod invoked on thread: " +
                Thread.CurrentThread.Name);
        }

        static void Main(string[] args) {
            //Control.CheckForIllegalCrossThreadCalls = true;
            TestThread myThread = new TestThread();
            Thread thread =
                new Thread(
                    new ThreadStart(myThread.ThreadTask)
                );
            thread.Name = "Alpha thread";
            thread.Start();
            Thread.Sleep(1000);
            if (myThread.Ctrl.InvokeRequired) {
                myThread.Ctrl.BeginInvoke(
                    new MethodInvoker(MyTestMethod)
                );
            } else {
                MyTestMethod();
            }
        }
    }
}




Check out here how to do the same thing in Java.