0

I have the following code:

public interface TestInterface
{
    [Display(Name = "Test Property")]
    int Property { get; }
}

class TestClass : TestAttribute
{
    public int Property { get; set; }
}

Note, that the property of interface is marked with DisplayAttribute. When I am trying to get the value from attribute, the following code samples does not works.

First sample: direct access to property of class.

var t = new TestClass();

var a = t.GetType().GetProperty("Property").GetCustomAttributes(true);

Second sample: cast object to interface and get access to property.

var t = (TestInterface)new TestClass();

var a = t.GetType().GetProperty("Property").GetCustomAttributes(true);

But when I am passing object as a model for mvc view and calling @Html.DisplayNameFor(x => x.Property) it returns the correct string "Test Property".

View

@model WebApplication1.Models.TestInterface
...
@Html.DisplayNameFor(x => x.Property)

renders as

Test Property

How can I achieve the same result with code on server side? And why I can not do it with simple reflection?

Mikhail Tulubaev
  • 4,141
  • 19
  • 31
  • Please see this question: [Can a C# class inherit attributes from an interface?](http://stackoverflow.com/questions/540749/can-a-c-sharp-class-inherit-attributes-from-its-interface). Basically, when you implement an interface, you need to redeclare the attributes. – Matias Cicero Jul 26 '16 at 13:03
  • Notice that `@Html.DisplayNameForm` works because you are working with `TestInterface`. instead of `TestClass`. – Matias Cicero Jul 26 '16 at 13:09
  • @Matias in the second code sample I am working with TestInterface too – Mikhail Tulubaev Jul 26 '16 at 13:12
  • But `GetType()` isn't called on the interface. The interface just hides the implementation. `GetType()` is called on the implementation, i.e. `TestClass`. – Matias Cicero Jul 26 '16 at 13:12
  • Well, what should I do to get property of interface? – Mikhail Tulubaev Jul 26 '16 at 13:14
  • You can use reflection, but you need to use the interface's type. See @grek40 answer for a possible solution. – Matias Cicero Jul 26 '16 at 13:15

3 Answers3

1

You can explicitely query the associated interface types for annotations:

var interfaceAttributes = t.GetType()
    .GetInterfaces()
    .Select(x => x.GetProperty("Property"))
    .Where(x => x != null) // avoid exception with multiple interfaces
    .SelectMany(x => x.GetCustomAttributes(true))
    .ToList();

The result list interfaceAttributes will contain the DisplayAttribute.

grek40
  • 13,113
  • 1
  • 24
  • 50
1

You can try this one

 var t = new TestClass();
 var a = t.GetType().GetInterface("TestInterface").GetProperty("Property").GetCustomAttributes(true);
Ebraheem
  • 603
  • 6
  • 24
  • This code will works but I need more generic solution, when I can not predict an interface name. @grek40's answer is the one what I need – Mikhail Tulubaev Jul 26 '16 at 13:26
  • I though you want the simplest solution, if you want a generic one you should start to play with Linq :) or use @grek40 answer it seems generic – Ebraheem Jul 26 '16 at 13:33
  • The simplest solution will be var a = "Test Property"; :) And I know that via linq and retrieving MemberInfo from MemberExpression I will get the required value. I hoped that I can do the same with text value of property name. – Mikhail Tulubaev Jul 26 '16 at 13:40
0

I have done something similar for the Description attribute. You could refactor this code (or better, make more generic) so it works for the Display attribute as well and not only for enums:

public enum LogCategories
{
    [Description("Audit Description")]
    Audit,
}


public static class DescriptionExtensions
{
    public static string GetDescription<T, TType>(this T enumerationValue, TType attribute)
        where T : struct
        where TType : DescriptionAttribute
    {
        Type type = enumerationValue.GetType();
        if (!type.IsEnum)
        {
            throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
        }

        //Tries to find a DescriptionAttribute for a potential friendly name
        //for the enum
        MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
        if (memberInfo != null && memberInfo.Length > 0)
        {
            object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attribute is DescriptionAttribute)
            {
                if (attrs != null && attrs.Length > 0)
                {
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
            }
            else
            {                   
            }                
        }
        //If we have no description attribute, just return the ToString of the enum
        return enumerationValue.ToString();
    }
}

As you see, the code uses some reflection to detect any attributes marked on the member (in my case the DescriptionAttribute but it could be the DisplayAttribute too) and returns the Description property to the caller.

Usage:

string auditDescription = LogCategories.Audit.GetDescription(); // Output: "Audit Description"
hbulens
  • 1,872
  • 3
  • 24
  • 45
  • Retrieving the member of passed object is similar to my first and second code sample. It will not works with interface. – Mikhail Tulubaev Jul 26 '16 at 13:25
  • There is no interface involved here so I don't understand what you're trying to say here. Could you elaborate? – hbulens Jul 26 '16 at 14:45