Click here to Skip to main content
15,891,905 members
Articles / Programming Languages / C#

Custom Attributes with Extension Methods: Resource Key

Rate me:
Please Sign up or sign in to vote.
4.00/5 (3 votes)
12 Jul 2011CPOL2 min read 20.7K   5   2
Using a custom attribute to contain a resource key

I picked up this technique in my last job to use a custom attribute to contain a resource key. The biggest benefit was all the enums in the system used this attribute which provided a way to translate that enum to text. Take a look at a sample enum:

C#
public enum Mode
{
    [AttributeResourceKey("lblInvalid")]
    Invalid,
    [AttributeResourceKey("lblReview")]
    Review,
    [AttributeResourceKey("lblCheckout")]
    Checkout,
    [AttributeResourceKey("lblOrdered")]
    Ordered
}

Each enum uses the AttributeResourceKey to specify the resource key defined in the resx file. Combined with an Extension Method, we can extend the enum itself to allow us to execute the following:

C#
public void DoOperation(Mode mode)
{
    Log.Info(GetResourceString(mode.ResourceKey()));
    ...
}

The C++ head in me thinks, “why are we using Reflection when a static function in a helper class could contain a switch statement to convert the enum to the resource key?”. Technically, this is sufficient and faster. However, the C# head in me loves the idea that the enum and the resource key are intimately tied together in the same file. There is no helper function to forget to update. The penalty of reading an attribute is a small price to pay to keep the enum and resource key together in order to increase overall maintainability.

So the first thing I am going to do is define a simple interface for my custom attributes.

C#
public interface IAttributeValue<T>
{
    T Value { get; }
}

All this interface does is define that the custom attribute class itself will define a property called Value of type T. This will be useful when using the generic method below for pulling the attribute. Next, we define the custom attribute class itself.

C#
public sealed class AttributeResourceKey : Attribute, IAttributeValue<string>
{
    private string _resourceKey;
    public AttributeResourceKey(string resourceKey)
    {
        _resourceKey = resourceKey;
    }

    #region IAttributeValue<string> Members
    public string Value
    {
        get { return _resourceKey; }
    }
    #endregion
}

Notice how simple the above class is. We have a constructor taking a string and a property called Value which returns the said string. Now let’s look at the generic method for pulling the attribute.

C#
public static class AttributeHelper
{
    /// <summary>
    /// Given an enum, pull out its attribute (if present)
    /// </summary>
    public static TReturn GetValue<TAttribute, TReturn>(object value)
    where TAttribute: IAttributeValue<TReturn>
    {
        FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
        object[] attribs    = fieldInfo.GetCustomAttributes(typeof(TAttribute), false);
        TReturn returnValue = default(TReturn);

        if (attribs != null && attribs.Length > 0)
            returnValue = ((TAttribute)attribs[0]).Value;

        return returnValue;
    }
}

Above is the heart of the code. It uses Generics so you need only define this code once in a static class. By passing the attribute and return type, we can extract our Value defined by IAttributeValue<TReturn>. Using the where constraint on TAttribute allows the generic method to know this type defines a property called Value of type TReturn. This exposes the true power of Generics as without this constraint, the method could only presume TAttribute is nothing more than an object. This might tempt you to wrongly cast TAttribute in order to access its properties, inviting an exception only seen at runtime.

Now to define our Extension Method, to be placed in a common namespace, to extend all enums with the ResourceKey() method.

C#
public static class EnumerationExtensions
{
    /// <summary>
    /// Given an enum, pull out its resource key (if present)
    /// </summary>
    public static string ResourceKey(this Enum value)
    {
        return AttributeHelper.GetValue<AttributeResourceKey, string>(value);
    }
}

Thanks to the generic attribute helper, the above Extension Method looks trivial. We simply use the helper to return the resource key and now we’ve extended all our enums to have this useful property.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Avaya Inc.
Ireland Ireland
Formerly a C++ client developer, nowadays I'm all about C# and ASP.NET. Over the years I have mastered some and played with many aspects of .NET.

Follow my blog as I catalogue the more arcane problems I encounter and their solutions at CodingLifestyle.com

Comments and Discussions

 
GeneralMy vote of 4 Pin
AndyHo18-Jul-11 13:03
professionalAndyHo18-Jul-11 13:03 
GeneralMy vote of 4 Pin
BloodyBaron18-Jul-11 10:53
BloodyBaron18-Jul-11 10:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.