The quirky ?:


If there was ever a poll conducted for the most favorite C# operator, I’d guess the conditional operator ?:, also known as the ternary operator, will win hands down. I find it to be one of those tools that make things shorter and clearer at the same time. But how well do you know the operator?



What do you think is wrong with the following piece of code?



    interface IDoer {}

    class ADoer : IDoer { }
    class BDoer : IDoer { }
    class Program
    {
        static void Main(string[] args)
        {
            bool flag = bool.Parse(args[0]);
            IDoer doer = flag ? new ADoer() : new BDoer();
        }
    }

Looks straightforward, doesn’t it? Yet, this does not compile; the error being



error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'ADoer' and 'BDoer'

The C# spec says that the two expressions that appear on either side of the : must be one of the following

  • Both of them should be of the same type
  • The first one should be convertible to the second
  • The second one should be convertible to the first


In the above case, ADoer and BDoer are both convertible to IDoer (because they implement IDoer), but because neither of them is implicitly convertible to the other, compilation fails. It doesn’t matter to the compiler that the result of the expression is always convertible to IDoer, all it cares about is the deduction of the type of the ternary expression.



I guess this is one of those places where static typing gets in the way of the developer, instead of helping him. You win some, you lose some :)



Playing with IronPython

I’ve been dabbling with IronPython for the last few days, trying to
host it and use it as a scripting engine. I have to say that I’m
impressed. The hosting API is incredibly simple to use and Mike Stall’s
blog served as a handy reference.



One thing I wanted my scripts to do was to access private and internal
members of types in the hosting application. I found that the command
line python interpreter (ipy.exe) had a -X:PrivateBinding switch to
allow access to private and internal members using the
<type>_<type>__memberName convention (which seems to be the
standard python name mangling for private members).



However, I couldn’t find an easy way to do that from the hosting
application. It was time to download the source code and figure out how
the command line option got translated in code. It turned out to be
pretty simple, there is a static class Options, which has properties
for most of the command line options. From the hosting application, all
you have to do is set the corresponding property before initializing
the PythonEngine.

void Initialize()
{
Options.PrivateBinding = true;
pythonEngine = new PythonEngine();
}

 

Add logs to the start and end of methods

 MethodLogger
is a macro I wrote that adds log statements at the beginning and ending
of all methods in the current document in Visual Studio. Unzip the
file, load it in Visual Studio using Tools->Macros->Load Macro
Project, open the appropriate C# file and then run the
LogMethodStartAndEnd macro. It transforms

class SomeClass
{
public void SomeMethod()
{
MessageBox.Show("Doodly doodly Doo");
}
}

to
class SomeClass
{
public void SomeMethod()
{
Console.WriteLine("Start of SomeClass.SomeMethod()");
try
{
MessageBox.Show("Doodly doodly Doo");
}
finally
{
Console.WriteLine("End of SomeClass.SomeMethod()");
}
}
}
The
code, written in VB .NET (which seems to be the only supported language
for writing macros?) uses Visual Studio’s automation interface to get
the code model for the currently open file. It then walks through all
the methods, figures out the starting and ending points of each method
and inserts the appropriate statements, with the most significant part
being the method signature. It does a very basic check (finds the first
non-empty, non comment line and checks if it’s the same as the text to
be logged) to make sure it doesn’t modify methods it has already added
logs to – when the user runs the macro twice, for example.


It should be fairly simple to change Console.WriteLine to something else – right clicking on LogMethodStartAndEnd and selecting Edit should take you to the Macro Editor IDE and lines 92, 93 contain the text to be inserted at the start and end of each method.

New version of deadlock detector

A new version of deadlock detector is up at Deadlock Detector^. This version is a partial rewrite, with a modified version of the algorithm to detect the object being locked. It now does a virtual execution of the IL, following through all control paths to find the locked object. There are a few issues with the execution logic, sometimes resulting in stack overflows and infinite loops. Any comments/suggestions/bug reports welcome.

How could this work?

I’m sure most of you know about BackgroundWorker, a new component in
.NET 2.0, that allows UI code to run tasks asynchronously, without
running into cross thread update issues. But what would happen if the
thread that launches the background worker is not a UI thread i.e. it
doesn’t run a message pump?

The answer is quite surprising and caused a piece of working code like this


AutoResetEvent waitForWorker = new AutoResetEvent(false);
void Method()
{
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_Completed)
worker.RunAsync();
waitForWorker.WaitOne();
}

void worker_Completed(...)
{
waitForWorker.Set();
}


to stop working after making a tiny modification like this

class MyForm : Form {}

AutoResetEvent waitForWorker = new AutoResetEvent(false);
void Method()
{
MyForm f = new MyForm();
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_Completed)
worker.RunAsync();
waitForWorker.WaitOne();
}

void worker_Completed(...)
{
waitForWorker.Set();
}


This caused Method() to hang indefinitely, because worker_Completed
never got to run. That makes sense, because the thread running method
is currently blocked on a call to waitForWorker.WaitOne() and
background worker would require that thread to be pumping messages to
get worker_Completed to run on that thread. But how did it work before?
The first code snippet also blocks on WaitOne(), yet worker_Completed
does run and everything works.



This is where things get interesting. A peek into BackgroundWorker via
Reflector revealed that it internally uses the new
AsyncOperationManager class to deal with running its event handlers
like ProgressChanged and RunWorkerCompleted on the thread that called
RunAsync. AsyncOperationManager is a general class that uses a
SynchronizationContext object to do its stuff and it’s
SynchronizationContext that does the heavy lifting of running code on
different threads. To get an instance of SynchronizationContext,
AsyncOperationManager tries to access the
SynchronizationContext.Current property, which retrieves the
corresponding instance for the current thread.



The default behavior of the SynchronizationContext class is to simply
delegate requests to run code on other threads to the threadpool. There
are subclasses of SynchronizationContext, like
System.Windows.Forms.WindowsFormsSynchronizationContext, that customize
the behavior to do something different.
WindowsFormsSynchronizationContext, for example, uses
Control.BeginInvoke internally to marshal code to run on the thread
that called RunAsync.



Can you see the problem now? Instantiating an instance of a Form
derived class caused the SynchronizationContext of the current thread
to change to WindowsFormsSynchronizationContext, which would use
Control.BeginInvoke. And that would not work unless the target thread
is pumping messages. The first sample worked because there was no
specific SynchronizationContext available, so an instance of the base
SynchronizationContext class itself is created. That would simply call
ThreadPool.QueueUserWorkItem to run the event handlers, which obviously
doesn’t require the target thread to be pumping.



The lesson – be wary of using BackgroundWorker from non-UI threads, the
behavior might change depending on objects previously instantiated on
the thread.