Getting the attributes of a field using reflection in C#

23.6k Views Asked by At

I wrote a method that extracts fields from an object like this:

private static string GetHTMLStatic(ref Object objectX, ref List<string> ExludeFields)
{
    Type objectType = objectX.GetType();
    FieldInfo[] fieldInfo = objectType.GetFields();

    foreach (FieldInfo field in fieldInfo)
    {
        if(!ExludeFields.Contains(field.Name))
        {
            DisplayOutput += GetHTMLAttributes(field);
        }                
    }

    return DisplayOutput;
}

Each field in my class also has it's own attributes, in this case my attribute is called HTMLAttributes. Inside the foreach loop I'm trying to get the attributes for each field and their respective values. It currently looks like this:

private static string GetHTMLAttributes(FieldInfo field)
{
    string AttributeOutput = string.Empty;

    HTMLAttributes[] htmlAttributes = field.GetCustomAttributes(typeof(HTMLAttributes), false);

    foreach (HTMLAttributes fa in htmlAttributes)
    {
        //Do stuff with the field's attributes here.
    }

    return AttributeOutput;
}

My attributes class looks like this:

[AttributeUsage(AttributeTargets.Field,
                AllowMultiple = true)]
public class HTMLAttributes : System.Attribute
{
    public string fieldType;
    public string inputType;

    public HTMLAttributes(string fType, string iType)
    {
        fieldType = fType.ToString();
        inputType = iType.ToString();
    }
}

This seems logical but it won't compile, I have a red squiggly line in the GetHTMLAttributes() method under:

field.GetCustomAttributes(typeof(HTMLAttributes), false);

The field I'm trying to extract the attributes from is in another class used like this:

[HTMLAttributes("input", "text")]
public string CustomerName;

From my understanding (or lack thereof) this should work? Please expand my mind fellow developers!

*Edit, compiler error:

Cannot implicitly convert type 'object[]' to 'data.HTMLAttributes[]'. An explicit conversion exists (are you missing a cast?)

I have tried casting it like this:

(HTMLAttributes)field.GetCustomAttributes(typeof(HTMLAttributes), false);

But that also doesn't work, I get this compiler error:

Cannot convert type 'object[]' to 'data.HTMLAttributes'

2

There are 2 best solutions below

1
On BEST ANSWER

GetCustomAttributes method returns an object[], not HTMLAttributes[]. The reason it returns object[] is that it has been there since 1.0, before .NET generics see the light of day.

You should manually cast each item in the return value to HTMLAttributes.

To fix your code, you simply need to change the line to:

object[] htmlAttributes = field.GetCustomAttributes(typeof(HTMLAttributes), false);

foreach will take care of the cast for you.

Update:

You shouldn't cast the returned array to HTMLAttributes[]. The return value is not HTMLAttributes[]. It's an object[] containing elements of type HTMLAttributes. If you want a HTMLAttribute[] typed object (which you don't need in this specific code snippet, foreach would suffice), you should cast each element of array individually to HTMLAttribute; perhaps using LINQ:

HTMLAttributes[] htmlAttributes = returnValue.Cast<HTMLAttributes>().ToArray();
0
On

If a class Person is decorated with Attributes like

public class Person
{
    [HTMLAttributes("input", "text")]
    public string CustomerName;

    [HTMLAttributes("string","charArray")]
    public string FirstName  = "FirstName";
        
    [HTMLAttributes("string","object")]
    public string LastName = "LastName";
}

You first needs to filter & find all the Fields which are decorated with HTMLAttributes, which can be done with linq

obj.GetType().GetFields()
.Where(_ => _.GetCustomAttributes(typeof(HTMLAttributes), true).Length >= 1  && _.Name == name)

Then you can cast it for your use with

GetCustomAttributes(typeof(HTMLAttributes), true).Cast<HTMLAttributes>()

Solution

The following Extension Method is coded to do that heavy work on any object.

public static class ObjectExtended //ExtensionClass
{
    public static T ReadAttribute<T>(this object obj,string name)
    {
        var all= obj.GetType().GetFields()
        .Where(_ => _.GetCustomAttributes(typeof(T), true).Length >= 1  && _.Name == name).FirstOrDefault();

        var attrib = all.GetCustomAttributes(typeof(T), true)
        .Cast<T>().FirstOrDefault();;
        
        return attrib;
    }
}

Example:

Since it is an extension method itis available next to the object. So in the main if we write:

void Main()
{
    var p = new Person();
    var attrib = p.ReadAttribute<HTMLAttributes>("CustomerName").Dump();
    
    attrib.fieldType.Dump();
    attrib.inputType.Dump();
}

and you can read the attribute value as below: enter image description here

Note: Dump() can be replace with Console.Write() or Console.WriteLine() when running in console