反映自定义属性时出错

本文关键字:出错 自定义属性 | 更新日期: 2023-09-27 18:03:54

我试图通过反射根据类的名称和自定义属性的存在获取类的某些字段的值。我的Custom属性是:

 [AttributeUsage (AttributeTargets.All, AllowMultiple=true)]
public sealed class ColumnAttribute : Attribute
{
    internal string name = "";
    internal string length = "";
    internal string precision = "";
    public ColumnAttribute() { }
    public ColumnAttribute(String name) { this.name = name; }
    public ColumnAttribute(String name, String length) { }
    public ColumnAttribute(String name, String length, String precision) { }
    public String Name { get { return name; } set { name = value; } }
    public String Length { get { return length; } set { length = value; } }
    public String Precision { get { return precision; } set { precision = value; } }
}
使用它的样例类是:
class SampleEntity
{
    //private int number;
    public string name;
    //float marks;
    public virtual int Number { get; set; }
    public SampleEntity() { }
    public SampleEntity(int number)
    {
        this.Number = number;
    }
    public void conversation(string request, string response) { }
    public void ordinary() {
        Console.Write("This isn't ordinary...");
    }
    [ColumnAttribute (Name = "XWBCCD")]
    public String XWBCCD { get; set; }
    [ColumnAttribute (Name = "XWBNCD")]
    public String XWBNCD { get; set; }

我还有一个不同的类它有不同的字段名:

 class SampleRepository
{
    [ColumnAttribute(Name = "XWBCCD")]
    public String SomeOtherFieldName { get; set; }
    [ColumnAttribute(Name = "XWBNCD")]
    public String XWBNCD { get; set; }
    [ColumnAttribute(Name = "XWBWCD")]
    public String XWBWCD { get; set; }
}

通过反射,我试图通过匹配属性'name'参数而不是字段名来复制值。问题是,在反射期间,这种比较不是通过传递字段的getCustomAttributes()方法进行的。我解决这个问题的方法是:首先,我传递了2个对象,objSrc(第一类,已填充)和objDesc(第二类,为空)

 FieldInfo[] srcFields = objSrc.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.IgnoreCase |BindingFlags.FlattenHierarchy);
        FieldInfo[] destFields = objDest.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty);

然后我尝试迭代地执行所有字段的反射

foreach (FieldInfo srcFld in srcFields)
        {
            foreach (FieldInfo destFld in destFields)
            {
                if (((MemberInfo)srcFld).Name.Equals(((MemberInfo)destFld).Name)){
                    destFld.SetValue(objDest, srcFld.GetValue(objSrc));
                    break;
                }
                object[] srcAttr = srcFld.GetCustomAttributes(true);
                object[] destAttr = destFld.GetCustomAttributes(true);
                if (Utils.Length(srcAttr) == 1 && Utils.Length(destAttr) == 1){
                    if ((srcAttr[0]).Equals(destAttr[0]) && srcFld.FieldType.Equals(destFld.FieldType))
                        destFld.SetValue(objDest, srcFld.GetValue(objSrc));
                    else
                        break;
                }
            }
        }

问题发生在GetCustomAttributes()方法上,因为它返回null。

反映自定义属性时出错

我为vb.net代码而不是c#道歉,但我碰巧有一个linqpad文件,我在那里做了完全相同的事情,在这里:

(不是真正的生产就绪代码,但我希望它能让你明白。)

Sub Main
    dim data as DataRow = GetSomeData.GetData(2311385).rows(0)
    dim dm as IDataMapper = new DataMapper()
    dim login as LoginData = dm.MapDataTo(of LoginData)(data)
    data.Dump()
    login.dump()
End Sub
public interface IDataMapper
    function MapDataTo(of T as {IDataMappable,new})(data as DataRow) as T
end interface
public interface IDataMappable
end interface
public class DataMapper
    implements IDataMapper
    Public Function MapDataTo(Of T As {New, IDataMappable})(ByVal data As System.Data.DataRow) As T Implements IDataMapper.MapDataTo
        dim mapToObj as new T
        dim properties() as PropertyInfo = gettype(T).GetProperties()
        for each propInfo as PropertyInfo in properties
            Dim attributes() As Attribute = propInfo.GetCustomAttributes(GetType(DataMappingAttribute), True)
            if attributes.length > 0 then
                Dim dataAttribute As DataMappingAttribute = CType(attributes(0), DataMappingAttribute)
                Dim column As String = dataAttribute.ColumnName
                Dim dataType As Type = dataAttribute.DataType
                propInfo.SetValue(mapToObj, Convert.ChangeType(data(column), dataType), Nothing)
            end if
        next
        return mapToObj
    end function
end class
<AttributeUsage(AttributeTargets.Property)> _
public class DataMappingAttribute
    inherits Attribute
    private _ColumnName as string
    Public readonly Property ColumnName() As String
        Get
            return _ColumnName
        End Get
    End Property
    private _DataType as Type
    Public readonly Property DataType() As Type
        Get
            return _DataType
        End Get
    End Property
    public sub new(ColumnName as string, DataType as Type)
        me._columnName = ColumnName
        me._DataType = DataType
    end sub 
end class

public class LoginData
    implements IDataMappable
    private _LoginID as integer
    <DataMappingAttribute("loginID",Gettype(integer))> _
    public property LoginID as integer
        get
            return _LoginID
        end get
        set(value as integer)
            _LoginID = value
        end set
    end property
    private _LoginName as string
    <DataMappingAttribute("loginName",Gettype(String))> _
    public property LoginName as string
        get
            return _LoginName
        end get
        set(value as string)
            _LoginName = value
        end set
    end property
    private _FirstName as string
    <DataMappingAttribute("firstName",Gettype(String))> _
    public property FirstName as string
        get
            return _FirstName
        end get
        set(value as string)
            _FirstName = value
        end set
    end property
    private _LastName as string
    <DataMappingAttribute("lastName",Gettype(String))> _
    public property LastName as string
        get
            return _LastName
        end get
        set(value as string)
            _LastName = value
        end set
    end property
    private _EmailAddress as string
    <DataMappingAttribute("emailAddress",Gettype(String))> _
    public property EmailAddress as string
        get
            return _EmailAddress
        end get
        set(value as string)
            _EmailAddress = value
        end set
    end property
end class
public class GetSomeData
    Public shared Function GetData(ByVal ID As Integer) As DataTable
            'return a datatable
    End Function
end class