Error while reflecting through custom attributes
I am trying to fetch the values of certain fields of a class based on their names and the presence of a customized attribute through reflection. My Custom attribute is :
[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; } }
}
A sample class that uses this is :
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; }
I am also having a different class that's having different field names :
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; }
}
Through reflection, I am trying to copy values by matching the attribute 'name' parameter rather than the fieldname. Trouble is, that during reflection, such comparison is not happening through getCustomAttributes() method passed over fields. My approach to solve this problem (That's failing so far ) has been : First I pass on 2 objects, objSrc (of first class, which is populated) and objDesc (of second class that's empty)
FieldInfo[] srcFields = objSrc.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.IgnoreCase |Bi开发者_开发知识库ndingFlags.FlattenHierarchy);
FieldInfo[] destFields = objDest.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty);
Then I am trying to iteratively perform reflection over all fields
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;
}
}
}
Trouble happens on the GetCustomAttributes() method as it is returning null.
I apologize for the vb.net code instead of c#, but I happen to have had a linqpad file where I was doing exactly the same thing, here ya go:
(Not really production ready code at all, but it gets the idea across I hope.)
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
精彩评论