通过自定义属性反映时出错

时间:2011-07-28 12:33:06

标签: c# .net custom-attributes system.reflection

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

 [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'参数而不是fieldname来复制值。 麻烦的是,在反射过程中,通过遍历字段的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。

1 个答案:

答案 0 :(得分:0)

我为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