Monday, November 19, 2007

 

DataGridView lockup in AdjustFillingColumns()

The other day, a WinForms application that I work on hung while resizing the form. Assuming that the lockup was somehow my/our fault, I naturally jumped in to investigate. As it turns out, the hang was not our fault at all.

The form was using a System.Windows.Forms.DataGridView control. I was able to attach my debugger to the process, and do a Break-All. The current thread was the UI thread, and the DataGridView's AdjustFillingColumns() method was at the top of the stack for that thread. After doing a run, wait a few seconds, and break-all several times, the current thread was always the UI thread and the AdjustFillingColumns() method was always on the top of the stack. Since task manager showed massive CPU usage while running and AdjustDataGridView() was always on top of the stack, it was a pretty good guess that the method was somehow in an infinite loop.

I used Reflector to look at the .NET code, and found 8 pages of nested if conditions and loops of every kinds. Luckily, I was able to use the Visual Studio Disassembler window to look at the assembly code and define the bounds of the loop in assembly code. Then, looking at the jumps and conditions of the assembly code, I was able to correlate it back to the Microsoft AdjustFillingColumns() source that was reverse-engineered by Reflector.

As it turns out, the AdjustFillingColumns() uses an iterative algorithm for determining the proper size of the auto-sized columns. Under certain conditions, the iterative algorithim does not converge and loops forever. The workaround is to not use any auto-sized columns, and instead calculate the column sizes in the application.

This issue has been reported to Microsoft. See the following Bug Report.

Upon re-reading this post, I realized that I forgot to specifically mention what I meant by "auto-sized columns". The problem I saw occurred when the DataGridViewColumn.AutoSizeMode property was set to DataGridViewAutoSizeColumnMode.Fill. I do not know if it occurs for other auto-size column modes.

Thursday, November 8, 2007

 

The C# ?, ?: and ?? operators

Most programmers are familar with the ternary or conditional assigment (?:) operator. This is by no means unique to C#, as similar operators exist in most modern programming languages. The previous posting entitled "String concatentation and null" included an example of one:


string myString = (someVariable != null) ? someVariable : "";

 

The example above is a short-hand equivalent of the following C# code.


string myString;
if (someVariable != null)
{
myString = someVariable;
}
else
{
myString = "";
}

 

But, when it comes to C#.NET 2.0 or later, there is an even quicker shorthand if the programmer wants to make conditional assigmnets on null. Enter the null assignment(??) operator. The following example is equivalent to the two examples above.


string myString = someVariable ?? "";

 

If the left hand side of the ?? operator (i.e. someVariable) is not null, then it is assigned as the value. But, if the left hand side of the operator is null, then the right hand side or the operator is assigned as the value.

One caveat to this is that someVariable is only evaluated once. This is not suprising, as it is only listed once. But, it does differ from the other two examples in which someVariable is evaluated twice: once for the condition, and once for the assignment. This is not likely to cause many problems, but is something to keep in mind if you were calling someMethod() instead of someVariable because it means the code is not necessarily a 100% compatible replacement for the earlier two examples.

In addition to the ternary (?:) and null assignment (??) operators, there is also a third way to use the question mark in C#.NET 2.0 and later. Enter the nullable type (?) operator!

As a .NET programmer, you are no doubt familar with value types verses reference types. Reference types can generally be null, or contain a reference to an instance of an object. Value types such as ints, on the other hand, cannot traditionally be null. The nullable type operator allows value types to be null, or any valid value! You can specify a type is nullable by putting a question mark after the type.


int nonNullableInt = 0;
int? nullableInt = null;

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]