C# 使用反射忽略具有自定义属性集的属性
我编写了一个泛型方法,该方法从Datatable生成泛型类型的集合。我寻找了不同的实现,但在处理大量属性和大量记录时,大多数实现的性能都非常差。到目前为止,这一次的表现相当不错 我试图通过在属性顶部添加一个自定义属性(DataField)来改进该方法,这样我就可以将其包含在属性中,并且可以跳过与列的匹配,或者为属性指定一个自定义名称以匹配datatable的列名 我看了代码,现在看起来像是一团糟,我真的不为它感到骄傲,我希望有一个更好的实现。有人能给我一些提示吗?非常感谢 试图加入评论,但不确定这有多大帮助。谢谢,以下是代码:C# 使用反射忽略具有自定义属性集的属性,c#,reflection,custom-attributes,C#,Reflection,Custom Attributes,我编写了一个泛型方法,该方法从Datatable生成泛型类型的集合。我寻找了不同的实现,但在处理大量属性和大量记录时,大多数实现的性能都非常差。到目前为止,这一次的表现相当不错 我试图通过在属性顶部添加一个自定义属性(DataField)来改进该方法,这样我就可以将其包含在属性中,并且可以跳过与列的匹配,或者为属性指定一个自定义名称以匹配datatable的列名 我看了代码,现在看起来像是一团糟,我真的不为它感到骄傲,我希望有一个更好的实现。有人能给我一些提示吗?非常感谢 试图加入评论,但不确定
private static void SetItemFromRow<T>(T item, DataRow row) where T : new()
{
// Get all properties with attributes.
PropertyInfo[] propWithAttributes = item.GetType().GetProperties().Where(x => Attribute.IsDefined
(x, typeof(DataField))).ToArray();
foreach (DataColumn col in row.Table.Columns)
{
// Find property that matches the column name.
PropertyInfo p = item.GetType().GetProperty(col.ColumnName);
bool ignoreProperty = false;
if (p != null)
{
// If no attribute exists set the property value. Break out from the loop to go to the next column (Property).
if (!propWithAttributes.Contains(p))
{
if (row[col] != DBNull.Value)
{
p.SetValue(item, row[col], null);
continue;
}
}
// If the property has a custom attribute then check if its ignore property is true. If so we break out from the loop and go to the next column (Property).
var attrs = p.GetCustomAttributes(typeof(DataField), false).ToArray() as DataField[]; ;
if (attrs != null)
foreach (var attr in attrs)
{
if (attr.Ignore)
ignoreProperty = true;
}
if (ignoreProperty) continue;
}
SetPropertyWithCustomName(item, propWithAttributes, row, col);
}
}
private static void SetItemFromRow(T item,DataRow行),其中T:new()
{
//获取具有属性的所有属性。
PropertyInfo[]propWithAttributes=item.GetType().GetProperties()。其中(x=>Attribute.IsDefined
(x,typeof(DataField))).ToArray();
foreach(row.Table.Columns中的DataColumn列)
{
//查找与列名匹配的属性。
PropertyInfo p=item.GetType().GetProperty(col.ColumnName);
bool ignoreProperty=false;
如果(p!=null)
{
//如果不存在属性,则设置属性值。从循环中断以转到下一列(属性)。
如果(!propWithAttributes.Contains(p))
{
if(行[col]!=DBNull.Value)
{
p、 设置值(项,行[col],空);
继续;
}
}
//如果该属性具有自定义属性,则检查其ignore属性是否为true。如果为true,我们将从循环中断并转到下一列(属性)。
var attrs=p.GetCustomAttributes(typeof(DataField),false).ToArray()作为DataField[];
如果(属性!=null)
foreach(属性中的var attr)
{
如果(属性忽略)
ignoreProperty=true;
}
如果(ignoreProperty)继续;
}
SetPropertyWithCustomName(项、propWithAttributes、行、列);
}
}
现在,我们在具有匹配列名的对象上设置了所有属性,并且跳过了所有要忽略的属性。最后一步是设置具有定义名称的DataField属性的属性
private static void SetPropertyWithCustomName<T>(T item, PropertyInfo[] propWithAttributes, DataRow row, DataColumn col)
where T : new()
{
foreach (var prop in propWithAttributes)
{
// Get the attributes for the property.
var attrs = prop.GetCustomAttributes(typeof(DataField), false).ToArray() as DataField[];
bool match = false;
if (attrs != null)
{
foreach (var attr in attrs)
{
// Check if the column name matches the custom name on the property.
if (col.ColumnName == attr.Name)
{
var p = item.GetType().GetProperty(prop.Name);
if (row[col] != DBNull.Value)
{
p.SetValue(item, row[col], null);
match = true;
break;
}
}
}
if (match) break;
}
}
}
private static void SetPropertyWithCustomName(T项,PropertyInfo[]propWithAttributes,DataRow行,DataColumn列)
其中T:new()
{
foreach(propWithAttributes中的var prop)
{
//获取属性的属性。
var attrs=prop.GetCustomAttributes(typeof(DataField),false).ToArray()作为数据字段[];
布尔匹配=假;
如果(属性!=null)
{
foreach(属性中的var attr)
{
//检查列名是否与属性上的自定义名称匹配。
if(col.ColumnName==attr.Name)
{
var p=item.GetType().GetProperty(prop.Name);
if(行[col]!=DBNull.Value)
{
p、 设置值(项,行[col],空);
匹配=真;
打破
}
}
}
如果(比赛)中断;
}
}
}
以下是您的代码的可读性更强的版本(如果我正确理解了意图):
private static readonly Dictionary\u propsCache=new Dictionary();
私有静态DataFieldProperty[]GetProperties(类型){
锁{
如果(!_propsCache.ContainsKey(类型)){
var result=新列表();
foreach(type.GetProperties(BindingFlags.Instance | BindingFlags.Public)中的var prop){
var attr=prop.GetCustomAttribute();
结果.添加(新的DataFieldProperty{
名称=属性名称??属性名称,
忽略=属性?忽略??错误,
属性=道具
});
}
_Add(type,result.ToArray());
}
返回_propsCache[类型];
}
}
私有类DataFieldProperty{
公共字符串名称{get;set;}
公共属性信息属性{get;set;}
公共布尔忽略{get;set;}
}
私有静态void SetItemFromRow(T item,DataRow行),其中T:new(){
//获取具有属性的所有属性。
var props=GetProperties(item.GetType());
foreach(row.Table.Columns中的DataColumn列){
//查找与列名匹配的属性。
var p=props.FirstOrDefault(c=>c.Name==col.ColumnName&&!c.Ignore);
如果(p!=null){
if(行[col]!=DBNull.Value){
p、 SetValue(项,行[col],空);
}
}
}
}
请注意,我并没有实际运行它(但已验证它是否编译)。以下是您代码的可读性更强的版本(如果我正确理解了意图):
private static readonly Dictionary\u propsCache=new Dictionary();
私有静态DataFieldProperty[]GetProperties(类型){
锁{
如果(!_propsCache.ContainsKey(类型)){
var result=新列表();
foreach(type.GetProperties(BindingFlags.Instance | BindingFlags.Public)中的var prop){
var attr=prop.GetCustomAttribute();
结果。添加(新)
private static readonly Dictionary<Type, DataFieldProperty[]> _propsCache = new Dictionary<Type, DataFieldProperty[]>();
private static DataFieldProperty[] GetProperties(Type type) {
lock (_propsCache) {
if (!_propsCache.ContainsKey(type)) {
var result = new List<DataFieldProperty>();
foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
var attr = prop.GetCustomAttribute<DataField>();
result.Add(new DataFieldProperty {
Name = attr?.Name ?? prop.Name,
Ignore = attr?.Ignore ?? false,
Property = prop
});
}
_propsCache.Add(type, result.ToArray());
}
return _propsCache[type];
}
}
private class DataFieldProperty {
public string Name { get; set; }
public PropertyInfo Property { get; set; }
public bool Ignore { get; set; }
}
private static void SetItemFromRow<T>(T item, DataRow row) where T : new() {
// Get all properties with attributes.
var props = GetProperties(item.GetType());
foreach (DataColumn col in row.Table.Columns) {
// Find property that matches the column name.
var p = props.FirstOrDefault(c => c.Name == col.ColumnName && !c.Ignore);
if (p != null) {
if (row[col] != DBNull.Value) {
p.Property.SetValue(item, row[col], null);
}
}
}
}