Monday, April 21, 2008

Instantiating a Class Without Calling Its Constructor

Recently I came across a situation where I wanted to create an instance of a specific class without the constructor logic being executed. My first intuition was to look if reflection had any means to circumvent the constructor logic. Reflection offers a way to instantiate a class by calling its constructor regardless of the constructor's access modifier.

// Call the parameterless constructor of MyClass via reflection.
Type t = typeof(MyClass);
ConstructorInfo ci = t.GetConstructor(System.Type.EmptyTypes);
MyClass o = (MyClass)ci.Invoke(null);

Unfortunately reflection didn't help much in bypassing the constructor logic. Next I thought about the Activator class and its CreateInstance method which supposedly creates an instance of a class by calling the best matching constructor.

// Call the parameterless constructor of MyClass using Activator.
MyClass o = (MyClass)Activator.CreateInstance(typeof(MyClass));

If the class doesn't have a constructor CreateInstance throws an exception. In other words I wasn't getting any closer to a solution. I was starting to run out of ideas until I recalled that the SoapFormatter can deserialize a file into an object without calling the class's constructor. Only when the class implements ISerializable interface will the special constructor that takes SerializationInfo and StreamingContext as parameters be called. So, how exactly do SoapFormatter as well as BinaryFormatter create instances of classes without calling their constructors? The instances are created by using the static GetUninitializedObject from the FormatterServices class that contains a number of static helper methods for formatters.

// Create an instance of a class without calling its constructor.
MyClass o = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass));

That's how easy it is. Of course this method should be used only when other methods for instantiating a class don't suit your needs as there probably is a minor performance hit associated with it.

Saturday, January 12, 2008

Static Members in Generic Classes

The other day I and Alessandro talked about how static members behave in generic classes. This might be blatantly obvious for most people but might cause some confusion for others. Imagine having a generic class of the following nature:

public class MyClass<T>
{
    private static string text = "uninitialized";

    public static string Text
    {
        get { return text; }
        set { text = value; }
    }
}

Now you're calling for example MyClass<string>.Text = "string"; — What do you think MyClass<int>.Text contains after this? Yup, it still contains the "uninitialized" string. This is due to the fact that at runtime native code is produced specifically for every type. In a sense you could think that there are two separate copies of the generic class, MyClass of string and MyClass of int which both have their own separate static members.

What if you actually wanted generic classes regardless of the type to share their static members? This is easily achieved by writing a separate static class and making the static members in the generic class act as wrappers for the members of the static class:

public class MyClass<T>
{
    public static string Text
    {
        get { return MyClassStatic.Text; }
        set { MyClassStatic.Text = value; }
    }
}

internal static class MyClassStatic
{
    private static string text = "uninitialized";

    public static string Text
    {
        get { return text; }
        set { text = value; }
    }
}

Now both MyClass<string>.Text and MyClass<int>.Text would refer to the same string.

Friday, December 14, 2007

Natural Sort in C#

Wilco Bauwer brought this article to my attention and as I'm always up for a good challenge I decided to give it a try. As I like regular expressions the first thing I decided was that I would use regular expressions to split the strings within the array instead of string methods and tokens. Now that that was out of the way I still needed to find a way to compare e.g. "10" and "5" so that "5" takes precedence. Obvious solution was to pad the strings with "0" so they would equal in length - i.e. the strings in the previous example would come "10" and "05" respectively. Enough of this chit chat as it's time to let the code speak for itself:

private static int CompareNaturally(string a, string b)
{
    MatchCollection m1 = Regex.Matches(a ?? "", @"\d+|[^\d]+");
    MatchCollection m2 = Regex.Matches(b ?? "", @"\d+|[^\d]+");

    for (int i = 0, c = 0; i < Math.Max(m1.Count, m2.Count); i++)
    {
        string s1 = i < m1.Count ? m1[i].Value : "";
        string s2 = i < m2.Count ? m2[i].Value : "";
        if (s1.Length > 0 && s2.Length > 0 && Char.IsDigit(s1[0]) && Char.IsDigit(s2[0]))
        {
            int len = Math.Max(s1.Length, s2.Length);
            c = s1.PadLeft(len, '0').CompareTo(s2.PadLeft(len, '0'));
        } else
            c = s1.CompareTo(s2);

        if (c != 0)
            return c;
    }

    return 0;
}

To use the above method for sorting an array one would simply use Array.Sort(myStringArray, CompareNaturally); where myStringArray is of course an array of strings. Wilco recommended I should use Regex.Replace() and MatchEvaluator to make it even shorter. So, here is a one-liner (okay, it's split on multiple lines but just for easier reading):

private static int CompareNaturally_Short(string a, string b)
{
    return Regex.Replace(a ?? "", @"\d+|[^\d]+", delegate(Match m) {
        return Char.IsDigit(m.Value[0]) ? m.Value.PadLeft(
            Math.Max(a.Length, b != null ? b.Length : 0), '0') : m.Value; 
    }).CompareTo(Regex.Replace(b, @"\d+|[^\d]+", delegate(Match m) {
        return Char.IsDigit(m.Value[0]) ? m.Value.PadLeft(
            Math.Max(a != null ? a.Length : 0, b.Length), '0') : m.Value; 
    }));
}
The idea behind this shorter version is pretty much the same with the exception that the MatchEvaluator takes care of padding the numeric strings. Don't hesitate contacting me or dropping a comment if you spot errors in either of the methods - Unfortunately I really didn't have time to test them thoroughly with different type of inputs.

Saturday, January 6, 2007

ASP.NET: Adding Style Property to Web Control

Let's start off with something relatively easy. There are some web controls in ASP.NET (Calendar, TreeView and Menu for instance) that allow you to change various aspects of their looks with style properties.

There are two ways to set a style property in .aspx file. First you can set the property as an attribute to the element that defines the control by concatenating the name of the style object with the property:

<asp:TreeView ID="TreeView1" runat="server"
    NodeStyle-CssClass="treeViewNode"/>

Another way is to write the style as its own element that is placed inside the element defining the control:

<asp:TreeView ID="TreeView1" runat="server">
    <NodeStyle CssClass="treeViewNode" />
</asp:TreeView>

Naturally the style can be defined in codebehind as well:

TreeView1.NodeStyle.CssClass = "treeViewNode";

Now, what if you want to add your own style property to your custom web control? The task is not that difficult but there are few things that need to be taken into consideration. First style object is what they call a complex object so writing a simple setter/getter property for the style in your custom control class doesn't cut it. Secondly you might want to store the style object to view state if you're going to change the style at some point and have the change persist.

We'll start off by adding an instance variable for the style object to the class:

private Style myCustomStyle = null;

Next we will add a property for the style:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
PersistenceMode(PersistenceMode.InnerProperty)]
public Style MyCustomStyle
{
    get
    {
        if (myCustomStyle == null)
        {
            myCustomStyle = new Style();
            // Set some default values here.

            if (IsTrackingViewState)
                ((IStateManager)myCustomStyle).TrackViewState();
        }

        return myCustomStyle;
    }
}

Notice how there is no setter part in the above property. The framework will call the getter and set properties directly to the object our getter provides. TrackViewState() is called to notify the framework that our style object should be tracked and changes to it should be saved as part of the control view state. We also add PersistenceMode(PersistenceMode.InnerProperty) to the property's metadata to specify that the property should persist as an inner property.

We are almost done but we still need to take care of view state. We want the view state for our style object to be loaded and saved at the same time with the control's view state. This is achieved by simply overloading the control's LoadViewState(), SaveViewState() and TrackViewState() methods as follows:

protected override void LoadViewState(object state)
{
    object[] states = (object[])state;

    base.LoadViewState(states[0]);
    ((IStateManager)MyCustomStyle).LoadViewState(states[1]);
}

protected override object SaveViewState()
{
    object[] states = new object[2];

    states[0] = base.SaveViewState();
    states[1] = (myCustomStyle != null) ? ((IStateManager)myCustomStyle).SaveViewState() : null;

    return states;
}

protected override void TrackViewState()
{
    base.TrackViewState();

    if (myCustomStyle != null)
        ((IStateManager)myCustomStyle).TrackViewState();
}

That's it! Now you should be able to use your style property just like with built-in ASP.NET controls. What you might still want to do is to apply the styles defined in the style object to the HTML code the control renders by overriding the control's Render() method.

Update (18 Mar 2007): I had a small typo in LoadViewState() method. Instead of accessing the myCustomStyle instance variable in the method, the property MyCustomStyle should have been accessed instead. Thanks to kal-EL@EFNet for pointing that out.

Friday, January 5, 2007

So, Why Yet Another Blog?

I'm very well aware that these days everybody and their mother has a blog and about 90 % of them are never read by anyone. The thing with this blog, though, is that I don't care at all whether someone reads it or not. I'm mainly going to use this as a place to gather some programming tips and tricks I've encountered so that I can access them quickly if I ever have the need. So, yeah, this is probably going to be a rather boring and geeky blog but fortunately no one is forced to read it (at least I hope so). However, if this blog actually manages to help someone then I've accomplished more than I originally expected.

I can't say I enjoy ranting about things but sometimes I just can't help myself. So don't be surprised if you occasionally find a blog entry that contains ranting and whining about something totally insignificant and unrelated. Consider yourself warned.