反映自定义属性时出错
本文关键字:出错 自定义属性 | 更新日期: 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