使用反射忽略具有自定义属性集的属性
Ignore properties with custom attribute set, using reflection
我编写了一个从数据表生成泛型集合的泛型方法。我一直在寻找不同的实现,但在处理大量属性和大量记录时,它们中的大多数在性能方面表现非常差。这个目前表现还不错。
我试图通过在属性之上添加自定义属性 ( DataField ) 来改进该方法,这样我就可以将它包含在属性中,我可以跳过将它与列匹配,或者指定一个自定义属性 的名称将匹配数据表的列名称。
我查看了代码,现在看起来一团糟,我真的不为此感到自豪,我想要一个更好的实现。谁能给我一些提示?非常感谢。
尝试添加评论但不确定有多大帮助。谢谢,这是代码:
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);
}
}
现在我们已经为具有匹配列名称的对象设置了所有属性,我们还跳过了所有我们想要忽略的属性。最后一步是设置具有已定义名称的 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 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);
}
}
}
}
请注意,我实际上并没有 运行 它(但验证它编译)。
我编写了一个从数据表生成泛型集合的泛型方法。我一直在寻找不同的实现,但在处理大量属性和大量记录时,它们中的大多数在性能方面表现非常差。这个目前表现还不错。
我试图通过在属性之上添加自定义属性 ( DataField ) 来改进该方法,这样我就可以将它包含在属性中,我可以跳过将它与列匹配,或者指定一个自定义属性 的名称将匹配数据表的列名称。
我查看了代码,现在看起来一团糟,我真的不为此感到自豪,我想要一个更好的实现。谁能给我一些提示?非常感谢。
尝试添加评论但不确定有多大帮助。谢谢,这是代码:
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);
}
}
现在我们已经为具有匹配列名称的对象设置了所有属性,我们还跳过了所有我们想要忽略的属性。最后一步是设置具有已定义名称的 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 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);
}
}
}
}
请注意,我实际上并没有 运行 它(但验证它编译)。