Jim's Software |  Jim and Katrin

Random development notes

The C# as Operator

1/01/2009  10:24 PM

It’s code review time!

The as operator is not the same thing as a cast. It is not better, it is different. It is appropriate in some situations, but not in others. Some people us it because they prefer the syntax, but it does different things, and the two are NOT interchangeable.

Using the as operator differs from a cast in C# in three important ways:

  1. It returns null when the variable you are trying to convert is not of the requested type or in its inheritance chain, instead of throwing an exception.
  2. It can only be applied to reference type variables converting to reference types.
  3. Using as will not perform user-defined conversions, such as implicit or explicit conversion operators, which casting syntax will do.

Number three is a good enough reason to prefer the cast as a general rule. By using the as operator you may be circumventing functionality that someone intentionally put into the class you’re referencing!

Here is a hard and fast rule for you:

IF YOU AREN’T GOING TO CHECK FOR THE NULL, DON’T USE THE as OPERATOR.

If there is a bug that results in the type you’re converting being the wrong type, you’ll get a null reference exception – possibly in code that is far from the as operator you used. Someone will have to debug that one day. And they’re going to waste time trying to figure out why the value is null, when they really need to be trying to figure out why the value is of the wrong type.

If you’re going to assume that the object is of a particular type, use the direct cast. This will result in an invalid cast exception, which is informative, and happens right there at the cast. The stack trace and the error message will tell someone precisely what happened and where:

System.InvalidCastException: Unable to cast object of type 'Foo' to type 'Bar'.

Now we know what went wrong – a NullReferenceException doesn’t tell us that.

WPF Templates

12/18/2008  2:40 PM

When copying Microsoft’s default templates for WPF controls, you might run into some unresolved tags:
<Trigger.Value>
    <s:Boolean>False</s:Boolean>
</Trigger.Value>

Where are that s:Boolean and the other ‘s’ prefixed tags thing common from? There in the System namespace; just add the prefix to your file like so:
xmlns:s="clr-namespace:System;assembly=mscorlib"
and you’re good to go.

Labels:

TypeExtension Problem

11/21/2008  11:38 AM

We were getting this error in the design view for our WPF application, only on some machines:

Could not create an instance of type 'TypeExtension'

The class reference was resolving correctly; if it doesn’t you get an error message to that effect. however the reference was to a class defined in a different project; this seemed to be the root of the problem.

Turns out this is a designer bug that is fixed in Visual Studio Service Pack 1. Check your version on Visual Studio’s about dialog; if you don’t see an “SP” in the version you need the service pack.

Pixel Snapping a DrawingVisual

11/13/2008  8:35 PM

image I’m drawing using the XSnappingGuidelines and YSnappingGuidelines to sharpen the edges of some lines in my 2D model. The usage of these was not entirely obvious to me from the documentation. Here it it in short:

A horizontal or vertical edge that falls on a guideline is snapped to the nearest pixel. The line is then filled away from the snapped edge to the pen thickness, blending for non-integers.

Edges and guidelines are both double values, and neither needs to fall on an integer value for snapping to occur. This can lead to some interesting effects.

The top section of lines in the image to the right are all drawn with a pen of width 1.0. The bottom lines are drawn with a pen of width 1.5. The lines are staggered by 0.1, so they don’t fall on pixel boundaries.

The columns are as follows:

  1. No snapping guidelines
  2. Snapping to line y position + 0.2
  3. Snapping to line y position
  4. Snapping to bottom edge of line
  5. Snapping to top and bottom edges of line

Option 4 is what we’re usually going to be looking for. This ensures that one edge is sharp, and all lines are drawn with consistent widths. In the case of integer width pens, this means two sharp edges. Of course this causes uneven spacing between lines, but that should rarely be this obvious.

Option 5 produces weird effects with the non-integer (1.5) pen; since both edges are snapped, the pen width is rounded to the nearest integer, and not consistently, resulting in lines with width 1 or 2. So this method makes the line thickness depend on the line position – probably not what you’re going for unless you want two sharp edges on a very thick line. 

Option 3 is what I would have expected to use; this causes the line to straddle the guideline. It always produces a symmetric line, and if the pen width is an even integer, it results in snapped edges

Option 2 is interesting; it causes the lines to draw consistently, although neither edge actually falls on the guideline. I’m not sure what the logic is here, and it seems that this could cause guidelines to affect shapes that they aren’t meant for.

Example project (Visual Studio 2008, .NET 3.5)