Add “extension properties” to classes in C#

[extension properties]

Extension methods allow you to add new methods to existing classes even if you don’t have access to the classes’ source code. For example, the Randomize two-dimensional arrays in C# example shows how to add an extension method to two-dimensional arrays holding data of an arbitrary type.

Unfortunately there is no way to make extension properties that add a property to an existing class. The usual solution, for controls at least, is to store extra values in an object’s Tag property. That works but only for controls and other classes that have a Tag property. It also preempts the Tag property for other uses and only allows you to store only one value.

This example adds SetValue and GetValue extension methods to the object class to allow you to set and get any number of new “property” values to any object.

The following code shows the ExtensionProperties class that adds the new extension methods.

public static class ExtensionProperties
{
    // Storage for the properties.
    private static Dictionary<object,
        Dictionary<string, object>>
        PropertyValues = new Dictionary<
            object, Dictionary<string, object>>();

    // Set a property value for the item.
    public static void SetValue(this object item,
        string name, object value)
    {
        // If we don't have a dictionary for this item yet,
        // make one.
        if (!PropertyValues.ContainsKey(item))
            PropertyValues[item] = new Dictionary<string, object>();

        // Set the value in the item's dictionary.
        PropertyValues[item][name] = value;
    }

    // Return a property value for the item.
    public static object GetValue(this object item, string name,
        object default_value)
    {
        // If we don't have a dictionary for
        // this item yet, return the default value.
        if (!PropertyValues.ContainsKey(item)) return default_value;

        // If the value isn't in the dictionary,
        // return the default value.
        if (!PropertyValues[item].ContainsKey(name))
            return default_value;

        // Return the saved value.
        return PropertyValues[item][name];
    }

    // Remove the property.
    public static void RemoveValue(this object item, string name)
    {
        // If we don't have a dictionary for this item, do nothing.
        if (!PropertyValues.ContainsKey(item)) return;

        // If the value isn't in the dictionary, do nothing.
        if (!PropertyValues[item].ContainsKey(name)) return;

        // Remove the value.
        PropertyValues[item].Remove(name);

        // If the dictionary is empty, remove it.
        if (PropertyValues[item].Count == 0)
            PropertyValues.Remove(PropertyValues[item]);
    }

    // Remove the object's property dictionary.
    public static void RemoveAllValues(this object item)
    {
        // If we have a dictionary for this item, remove it.
        if (PropertyValues.ContainsKey(item))
            PropertyValues.Remove(PropertyValues[item]);
    }
}

The class starts by declaring a Dictionary named PropertyValues that uses objects for keys and other Dictionary objects for values. It will look up an object in the top-level Dictionary to get the new property Dictionary for that object.

The “inner” Dictionary uses strings (the names of the “extension properties”) for keys and objects for values. Once the code finds an object’s “inner” Dictionary, it uses it to look up values.

The SetValue method saves a named “extension property” value for an object. First it determines whether the object has an entry in the PropertyValues Dictionary. If there is no such Dictionary yet, the method adds it. The SetValue method then uses the new or existing Dictionary object’s index method to store the desired “extension property” value.

The GetValue method also starts by determining whether the PropertyValues Dictionary contains a dictionary for the object. If there is no such Dictionary, the method returns the default value passed into it as a parameter.

If the “inner” Dictionary does exist, the method determines whether it contains a value for the desired “extension property.” If there is no such value, the method again returns the default value. Finally if the “inner” Dictionary contains a value for the desired “extension property,” the method returns it.

The RemoveValue method removes a value from the Dictionary objects. If the top-level PropertyValues Dictionary doesn’t contain an entry for the object, the method does nothing. Finally if the “inner” Dictionary contains a value for the “extension property,” the code removes it. Finally if the “inner” Dictionary is empty, the code removes it from the top-level PropertyValues Dictionary so it doesn’t become cluttered with Dictionary objects that are no longer needed.

Finally the RemoveAllValues method removes an object’s “inner” Dictionary. Before you destroy an object to which you have assigned “extension properties” via these extension methods, you should delete all of its properties. If you don’t, then they will continue to take up space in the Dictionaries. Even worse, the entries in the Dictionary objects will hold references to the objects themselves so they cannot easily be reclaimed by the garbage collector. They’ll be reclaimed eventually, but not as efficiently as they would if you remove the values.

The following code shows how the program uses extension properties.

// Set the value for the txtName TextBox.
private void btnSetValue_Click(object sender, EventArgs e)
{
    txtName.SetValue(txtName.Text, txtValue.Text);
    txtValue.Clear();
}

// Get the value from the txtName TextBox.
private void btnGetValue_Click(object sender, EventArgs e)
{
    txtValue.Text = txtName.GetValue(txtName.Text, "").ToString();
}

// Remove the value from the txtName TextBox.
private void btnRemoveValue_Click(object sender, EventArgs e)
{
    txtName.RemoveValue(txtName.Text);
    txtValue.Clear();
}

When you click the Set Value button, the program calls the txtName text box’s SetValue method passing it the name of the property and the value to assign to it.

When you click the Get Value button, the program calls the text box’s GetValue method passing it the name of the property and a default value, and displays the result.

When you click the Remove Value button, the program calls the text box’s RemoveValue method passing it the name of the property to remove.

The syntax isn’t quite as simple as using a property but it’s pretty easy. It’s comparable to the way the ToolTip component works.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in algorithms, classes, extension methods and tagged , , , , , , , , , . Bookmark the permalink.

One Response to Add “extension properties” to classes in C#

  1. Ramblings says:

    Ramblings

    BLOG.CSHARPHELPER.COM: Add “extension properties” to classes in C#

Leave a Reply

Your email address will not be published. Required fields are marked *