Taoffi's blog

prisonniers du temps

Xamarin: the missing Description attribute

If you are a Windows C# programmer, you may know about the DescriptionAttribute and its help in describing an object, a property, method or any other member of a class in a human way.

You may also use [Description], to associate a Label to a property and later use it in the UI.

As Xamarin.Forms does not (yet) offer this simple useful attribute, I decided to write one.

The basic code

Our Description attribute class is quite simple:

[AttributeUsage(validOn: AttributeTargets.All, AllowMultiple = false, Inherited = false)]
public class DescriptionAttribute : Attribute
{
    public string _description;

    public DescriptionAttribute(string description)
    {
         _description = description;
    }

    public string Description
    {
        get { return _description; }
        set { _description = value; }
    }
} 

 

With this in place, we can now write things like:

[Description("This is my object")]
public class MyClass
{
    [Description("This is my constructor")]
    public MyClass()
    {
    }

    [Description("My property")]
    public string Property1
    {
     … 
    }

 

 

Reading back the descriptions

Well, but for this to be useful, we must do something to get back these descriptions when needed.

First: how to read the descriptions assigned to objects and members?

Some extension helpers can simplify this work (remember: we are in portable (PCL) library, and also using System.Reflection):

public static string Description(this Type objectType)
{
    if(objectType == null)
        return null;

    TypeInfo typeInfo = objectType.GetTypeInfo();
    var attrib = typeInfo.GetCustomAttribute<DescriptionAttribute>();
    return attrib == null ? null : attrib.Description;
}



To get the description of MyClass, The above extension method now allows us to write:

string    classDescription    = typeof(MyClass).Description();

 

Another method may even make that simpler: get the description of an object's instance of a given class:

public static string Description(this object obj)
{
    if(obj == null)
        return null;

    return obj.GetType().Description();
}


 

This allows us to write: myObject.Description(); to get the description of myObject's class.

Reading back the description of class members

Reading a given member (property / method…) description, we have to look into the MemberInfo object of that given member to find the Description attribute:

 

public static string MemberDescription(this MemberInfo member)
{
    if(member == null)
        return null;

    var attrib = member.GetCustomAttribute<DescriptionAttribute>();
    return attrib == null ? null : attrib.Description;
}

 

 

How to get a member info? Not quite handy!...

Let us simplify a little more. The following code (though it may be somehow difficult to read… see System.Linq.Expressions) will allow a much easier syntax.

 

public static string PropertyDescription<TMember>( Expression<Func<TMember>> memberExpression)
{
    if (memberExpression == null)
        return null;

    var expression = memberExpression.Body as MemberExpression;
    var member = expression == null ? null : expression.Member;

    if (member == null)
        return null;

    return member.MemberDescription();
}

 

 

The above method analyses its Expression parameter to extract the MemberInfo for us and calls the original method to extract the description of the member.

To use this method to extract the description of 'Property1' , we can write:

string propertyLabel = PropertyDescription(()=> Property1);

 

What about Enums?

As you know, we often give short (occasionally cryptic!) names for enum members. Displaying these names in a clear human-readable manner to the user for selecting a value is usually a challenge.

The Description attribute can help us assign these labels. Reading them back is somehow another challenge. The reason is that enum members are fields (in contrast to member properties and methods we saw before)

Actually, with enums, we have two challenges: find the description of each element, but also be able to retrieve the value of a selected description.

For the first challenge, find the description of an element, let us try this extension:

 

public static string EnumDescription(this Enum value)
{
    if(value == null)
        return null;

    var type = value.GetType();
    TypeInfo typeInfo = type.GetTypeInfo();
    string typeName = Enum.GetName(type, value);

    if (string.IsNullOrEmpty(typeName))
        return null;

    var field = typeInfo.DeclaredFields.FirstOrDefault(f => f.Name == typeName);

    if(field == null)
        return typeName;

    var attrib = field.GetCustomAttribute<DescriptionAttribute>();
    return attrib == null ? typeName : attrib.Description;
}

 

 

Sample usage:

 

public enum Flowers
{
    [Description("African lily")]
    Agapanthus,

    [Description("Alpine thistle")]
    Eryngium,

    [Description("Amazon lily")]
    Eucharis,
};

 

string africanLilly = Flowers.Agapanthus.EnumDescription(); //"African lily"
string alpineThistle = Flowers.Eryngium.EnumDescription(); //"Alpine thistle"

 

Find the enum value by its description

The second task is to retrieve the enum value by its description. For instance when the user selects one of the displayed descriptions.

 

public static int EnumValue(this Enum value, string selectedOption)
{
    var values = Enum.GetValues(value.GetType());

    foreach(Enum v in values)
    {
        string description = v.EnumDescription();

        if(description == selectedOption)
            return (int) v;
    }

    return 0; // arbitrary default value
}

 

 

Now we can write:

 

Flowers africanLilly = Flowers.EnumValue("African lily");    // Agapanthus
Flowers amazonLilly = Flowers.EnumValue("Amazon lily");    // Eucharis