Two Minor C# Tips and Tricks

In a desperate attempt to get my blog posting rate up, I'll throw up two minor C# tips.

  1. C# 3.0, we can now extend classes without subclassing them. If this sounds like theĀ controversial practice of monkeypatching ninjapatching, it's not, exactly, because your extensions to the class in question are only available to your code. I.e. they are not patched into the actual class being used everywhere.

    There's lots of places you might want to add extension methods. One that we've used recently is to extend enums. Enums are sealed off in C#, so you can't subclass it. We wanted to add attributes to our enums (in our case, detailing some plain language names for the enumerations), and then add extension methods to the Enum class that would allow us to get the attribute details. We didn't come up with the idea, we stole it.

    For us, we now have code like:

    /// <summary>
    /// Enums that are used to build the path menu
    /// </summary>
    public enum PathBuilderMenuType
    {
        /// <summary>
        /// Unknown PathBuilderButtonType
        /// </summary>
        Unknown,

        /// <summary>
        /// Author menu item
        /// </summary>
        [LocalizedDisplayStringAttribute("OptionsMenuAuthor")]
        Author,

        /// <summary>
        /// Book menu item
        /// </summary>
        [LocalizedDisplayStringAttribute("OptionsMenuBook")]
        Book,

        /// Publisher menu item
        /// </summary>
        [LocalizedDisplayStringAttribute("OptionsMenuPublisher")]
        Publisher
    }

    that we can then get friendly name from our language table with something like ...
    private PathBuilderButton CreateButton(PathBuilderMenuType buttonType, ContextMenu menu)
    {
        PathBuilderButton button = new PathBuilderButton(Type, buttonType);    
        button.Content = _language.GetString(buttonType.GetLanguageKey());
    }

    where the GetLanguageKey() is an extension method defined on the Enum class that returns the attribute value LocalizedDisplayStringAttribute

  2. Symbolic Debugging: this is an oldy but a goody. The Visual Studio debugger defaults to using the ToString() method as its shorthand representation of objects in the debugger. However, there are times where you want to have the debugger's shorthand be different than ToString(). For that you can use:

    #if DEBUG
    [System.Diagnostics.DebuggerDisplay("Book {Title} {Author} {Publisher}")]
    #endif
    public class Book

    which gives some useful info right away. (the items in {} are properties of the object). Where this can be really helpful is if you are deep in the call stack in a callback method (say from NHibernate) and you don't know how you got there -- the call stack will now show you which objects got you there, even if you can't put a breakpoint in parts of the call stack code that you didn't write.

Hope these help.