使用反射在C#中获取字段的属性

3

我编写了一个方法,从对象中提取字段,就像这样:

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;
}

我的类中的每个字段都有自己的属性,这种情况下我的属性称为HTMLAttributes。在foreach循环内部,我正在尝试获取每个字段的属性及其相应的值。它目前看起来像这样:

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;
}

我的属性类看起来是这样的:

[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();
    }
}

这看起来很合理,但是它无法编译,GetHTMLAttributes() 方法下面有一条红色的波浪线:
field.GetCustomAttributes(typeof(HTMLAttributes), false);

我正在尝试从另一个类中提取属性的字段,用法如下:

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

据我的理解(或者说是不理解),这应该能起作用吧?请各位开发者拓宽我的视野!

*编辑,编译器错误:

无法隐式将类型 'object[]' 转换为 'data.HTMLAttributes[]'。显式转换存在(你是否缺少了强制类型转换?)

我已经尝试过像这样进行强制类型转换:

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

但是这也不起作用,我得到了这个编译器错误:
无法将类型为'object[]'的值转换为'data.HTMLAttributes'

如果您能告诉我们您遇到了哪个错误,也许有人可以帮忙解决。 - codymanix
更新了带有编译器错误的问题。 - Mr. Smith
2个回答

16

GetCustomAttributes 方法返回的是一个 object[],而不是 HTMLAttributes[]。它返回 object[] 的原因是在 .NET 泛型出现之前已经存在于 1.0 版本中。

你需要手动将返回值中的每个项转换为 HTMLAttributes

要修复您的代码,您只需要更改该行:

object[] htmlAttributes = field.GetCustomAttributes(typeof(HTMLAttributes), false);
foreach会自动为您执行强制类型转换。

更新:

不应该将返回的数组强制转换为HTMLAttributes[]。返回值不是HTMLAttributes[],而是包含HTMLAttributes类型元素的object[]数组。如果您需要一个HTMLAttribute[]类型的对象(在这个特定的代码片段中您不需要),使用foreach即可;如果确实需要转换,可以使用LINQ将数组的每个元素单独转换为HTMLAttribute
HTMLAttributes[] htmlAttributes = returnValue.Cast<HTMLAttributes>().ToArray();

C# 已经支持泛型形式的 GetCustomAttribute<>() 一段时间了。 - Huacanacha

0
如果一个类`Person`被修饰为如下的属性
public class Person
{
    [HTMLAttributes("input", "text")]
    public string CustomerName;

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


你首先需要过滤和查找所有用HTMLAttributes装饰的Fields,可以使用linq来完成。
obj.GetType().GetFields()
.Where(_ => _.GetCustomAttributes(typeof(HTMLAttributes), true).Length >= 1  && _.Name == name)

然后你可以使用cast将其转换为你需要的形式。
GetCustomAttributes(typeof(HTMLAttributes), true).Cast<HTMLAttributes>()

解决方案

下面的扩展方法被编码用于在任何对象上执行繁重的工作。

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;
    }
}

例子:

由于它是一个扩展方法,它可以在对象旁边使用。因此,在主函数中,如果我们写:

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

你可以按照以下方式读取属性值: enter image description here 注意:在控制台运行时,可以将Dump()替换为Console.Write()Console.WriteLine()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接