Reputation: 2696
I'm creating a library which relies on capturing the SynchronizationContext in order to post callbacks back to the UI thread.
A user was having a weird condition where the callbacks were being posted to the ThreadPool instead. After investigating a bit, I came up with the following two test cases:
public partial class Form1 : Form
{
private Test test;
public Form1()
{
test = new Test();
InitializeComponent();
}
private class Test
{
public Test()
{
if (SynchronizationContext.Current == null)
throw new InvalidOperationException("It's null! :(");
}
}
}
public partial class Form1 : Form
{
private Test test = new Test();
public Form1()
{
InitializeComponent();
}
private class Test
{
public Test()
{
if (SynchronizationContext.Current == null)
throw new InvalidOperationException("It's null! :(");
}
}
}
The 1st test runs fine, but the 2nd one throws an exception. Why?
Upvotes: 2
Views: 137
Reputation: 171246
In the second example new Test()
runs (almost) as the very first code in the program. Probably, your Main
function calls new Form1()
which immediately calls new Test()
.
A SynchronizationContext
must be set before it is present (obviously). There is nothing magic in the runtime that guesses that your app will use WinForms. Using WinForms is a dynamic runtime decision. WinForms will set its SynchronizationContext
when you use WinForms (I forgot the exact trigger points).
In the first example the base
constructor (new Form()
) runs first which apparently installs the SynchronizationContext
.
When you run code before any WinForms code runs no SynchronizationContext
will/can be present.
There is nothing sane that your library can do about this. You could add an assert or manually set the WinForms sync context (there is a API for that) but that is hardly the business of a library. Libraries are not supposed to mess with global state. (Except if your library is clearly meant for WinForms-only use).
Upvotes: 2