views:

1102

answers:

4

How do you access the Description property on either a const or a property, i.e.,

public static class Group
{

    [Description( "Specified parent-child relationship already exists." )]
    public const int ParentChildRelationshipExists = 1;

    [Description( "User is already a member of the group." )]
    public const int UserExistsInGroup = 2;

}

or

public static class Group
{

    [Description( "Specified parent-child relationship already exists." )]
    public static int ParentChildRelationshipExists { 
      get { return 1; } 
    }

    [Description( "User is already a member of the group." )]
    public static int UserExistsInGroup { 
      get { return 2; } 
    }

}

In the calling class I'd like to access the Description property, i.e.,

int x = Group.UserExistsInGroup;
string description = Group.UserExistsInGroup.GetDescription(); // or similar

I'm open to ideas to other methodologies as well.

EDIT: I should have mentioned that I've seen an example provided here: http://stackoverflow.com/questions/464889/does-auto-implemented-properties-support-attributes

However, I'm looking for a method to access the description attribute without having to enter a string literal into the property type, i.e., I'd rather not do this:

typeof(Group).GetProperty("UserExistsInGroup");

Something along the lines of an Extension Method; similar to the following method that will return the Description attribute on an Enum via an Extension Method:

public static String GetEnumDescription( this Enum obj )
{
    try
    {
        System.Reflection.FieldInfo fieldInfo = 
            obj.GetType().GetField( obj.ToString() );

        object[] attribArray = fieldInfo.GetCustomAttributes( false );

        if (attribArray.Length > 0)
        {
            var attrib = attribArray[0] as DescriptionAttribute;

            if( attrib != null  )
                return attrib.Description;
        }
        return obj.ToString();
    }
    catch( NullReferenceException ex )
    {
        return "Unknown";
    }
}
+3  A: 

Try the following

var property = typeof(Group).GetProperty("UserExistsInGroup");
var attribute = property.GetCustomAttribute(typeof(DescriptionAttribute), true)[0];
var description = (Description)attribute;
var text = description.Description;
JaredPar
@JaredPar - sorry, I should have clarified, please see my edit.
Metro Smurf
+2  A: 

You can call MemberInfo.GetCustomAttributes() to get any custom attributes defined on a member of a Type. You can get the MemberInfo for the property by doing something like this:

PropertyInfo prop = typeof(Group).GetProperty("UserExistsInGroup",
    BindingFlags.Public | BindingFlags.Static);
Andy
@Andy - sorry, I should have clarified, please see my edit.
Metro Smurf
I don't think that is possible, at least using attributes as you are. You need to get the PropertyInfo for the property, and the only way to do that is to search for it via the name of the property.
Andy
+1  A: 

Okay, I've seen your edit, I'm not sure you can do it with extension methods, as they would be anaware of the type of the containing class.

This is going to sound a little wacky, but how about creating a new class a "DescribedInt", which would have an implicit cast operator to let you use it as an int automatically? You'll be able to use pretty much how you describe. You'll still have a description, but when you need to use it like an Int, you wont' need to get the .Data property...

eg:

private void ExampleUse()
{
    int myvalue = Group.A; //see, no need to cast or say ".Data" - implicit cast
    string text = Group.A.Description;

//do stuff with values... }

public static class Group
{
    public static DescribedInt A = new DescribedInt(12, "some description");
    public static DescribedInt B = new DescribedInt(88, "another description");
}

public class DescribedInt
{
    public readonly int data;
    public readonly string Description;

    public DescribedInt(int data, string description)
    {
        this.data = data;
        this.Description = description;
    }

    //automatic cast to int
    public static implicit operator int(DescribedInt orig)
    {
        return orig.data;
    }

    //public DescribedInt(string description)
    //{
    //    this.description = description;
    //}

    //if you ever need to go the "other way"
    //public static implicit operator DescribedInt(int orig)
    //{
    //    return new DescribedInt(orig, "");
    //}
}
Ilya Tchivilev
@Ilya - this may be a viable alternative. I'll take a close look tomorrow. Thanks!
Metro Smurf
A: 

Here is a helper class I am using for processing custom attributes in .NET

public class AttributeList : List<Attribute>
{
    /// <summary>
    /// Gets a list of custom attributes
    /// </summary>
    /// <param name="propertyInfo"></param>
    /// <returns></returns>
    public static AttributeList GetCustomAttributeList(ICustomAttributeProvider propertyInfo)
    {
        var result = new AttributeList();
        result.AddRange(propertyInfo.GetCustomAttributes(false).Cast<Attribute>());
        return result;
    }

    /// <summary>
    /// Finds attribute in collection by its type
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T FindAttribute<T>() where T : Attribute
    {
        return (T)Find(x => typeof(T).IsAssignableFrom(x.GetType()));
    }

    public bool IsAttributeSet<T>() where T : Attribute
    {
        return FindAttribute<T>() != null;
    }
}

Also unit tests for MsTest showing how to use this class

[TestClass]
public class AttributeListTest
{
    private class TestAttrAttribute : Attribute
    {
    }

    [TestAttr]
    private class TestClass
    {
    }

    [TestMethod]
    public void Test()
    {
        var attributeList = AttributeList.GetCustomAttributeList(typeof (TestClass));
        Assert.IsTrue(attributeList.IsAttributeSet<TestAttrAttribute>());
        Assert.IsFalse(attributeList.IsAttributeSet<TestClassAttribute>());
        Assert.IsInstanceOfType(attributeList.FindAttribute<TestAttrAttribute>(), typeof(TestAttrAttribute));
    }
}

http://www.kozlenko.info/2010/02/02/getting-a-list-of-custom-attributes-in-net/

Maksym Kozlenko