Ошибка при отражении через пользовательские атрибуты - PullRequest
0 голосов
/ 28 июля 2011

Я пытаюсь получить значения определенных полей класса на основе их имен и наличия настраиваемого атрибута посредством отражения. Мой пользовательский атрибут:

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

Посредством размышления я пытаюсь скопировать значения, сопоставляя параметр «имя» атрибута, а не имя поля. Проблема в том, что во время отражения такое сравнение не происходит с помощью метода 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 голосов
/ 28 июля 2011

Я прошу прощения за код 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
...