C# GetCustomAttributes性能问题(表达式树是解决方案??)
我有一个性能问题,因为我使用反射和GetCustomAttributes进行数据访问。性能分析器检测到它。我有这样一个扩展方法:C# GetCustomAttributes性能问题(表达式树是解决方案??),c#,performance,reflection,expression-trees,C#,Performance,Reflection,Expression Trees,我有一个性能问题,因为我使用反射和GetCustomAttributes进行数据访问。性能分析器检测到它。我有这样一个扩展方法: public static class DataRowExtensions { /// <summary> /// Maps DataRow objecto to entity T depending on the defined attributes. /// </summary> /// <typep
public static class DataRowExtensions
{
/// <summary>
/// Maps DataRow objecto to entity T depending on the defined attributes.
/// </summary>
/// <typeparam name="T">Entity to map.</typeparam>
/// <param name="rowInstance">DataRow instance.</param>
/// <returns>Instance to created entity.</returns>
public static T MapRow<T>(this DataRow rowInstance) where T : class, new()
{
//Create T item
T instance = new T();
IEnumerable<PropertyInfo> properties = typeof(T).GetProperties();
MappingAttribute map;
DataColumn column;
foreach (PropertyInfo item in properties)
{
//check if custom attribute exist in this property
object[] definedAttributes = item.GetCustomAttributes(typeof(MappingAttribute), false);
// Tiene atributos
if (definedAttributes != null && definedAttributes.Length == 1)
{
//recover first attribute
map = definedAttributes.First() as MappingAttribute;
column = rowInstance.Table.Columns.OfType<DataColumn>()
.Where(c => c.ColumnName == map.ColumnName)
.SingleOrDefault();
if (column != null)
{
object dbValue = rowInstance[column.ColumnName];
object valueToSet = null;
if (dbValue == DBNull.Value)//if value is null
valueToSet = map.DefaultValue;
else
valueToSet = dbValue;
//Set value in property
setValue<T>(instance, item, valueToSet);
}
}
}
return instance;
}
/// <summary>
/// Set "item" property.
/// </summary>
/// <typeparam name="T">Return entity type</typeparam>
/// <param name="instance">T type instance</param>
/// <param name="item">Property name to return value</param>
/// <param name="valueToSet">Value to set to the property</param>
private static void setValue<T>(T instance, PropertyInfo item, object valueToSet) where T : class, new()
{
if (valueToSet == null)
{
CultureInfo ci = CultureInfo.InvariantCulture;
if (item.PropertyType.IsSubclassOf(typeof(System.ValueType)))
{
//if is a value type and is nullable
if (item.PropertyType.FullName.Contains("System.Nullable"))
{
item.SetValue(instance, null, BindingFlags.Public, null, null, ci);
}
else
{
item.SetValue(instance, Activator.CreateInstance(item.PropertyType, null), BindingFlags.Public, null, null, ci);
}
}
else //property type is reference type
{
item.SetValue(instance, null, BindingFlags.Public, null, null, ci);
}
}
else // set not null value
{
//if is a value type and is nullable
if (item.PropertyType.FullName.Contains("System.Nullable"))
{
item.SetValue(instance, Convert.ChangeType(valueToSet, Nullable.GetUnderlyingType(item.PropertyType)), null);
}
else
{
item.SetValue(instance, Convert.ChangeType(valueToSet, item.PropertyType), null);
}
}
}
}
我读到一个可能的改进是表达式树,但是,首先,我不是表达式树专家,其次,我必须用.NET3.5解决这个问题…(在示例中使用.NET4或4.5…)
什么建议
提前感谢。公共静态类DataRowExtensions
public static class DataRowExtensions
{
/// <summary>
/// Maps DataRow objecto to entity T depending on the defined attributes.
/// </summary>
/// <typeparam name="T">Entity to map.</typeparam>
/// <param name="rowInstance">DataRow instance.</param>
/// <returns>Instance to created entity.</returns>
public static T MapRow<T>( this DataRow rowInstance ) where T : class, new()
{
//Create T item
var instance = new T();
Mapper<T>.MapRow( instance, rowInstance );
return instance;
}
#region Nested type: Mapper
private static class Mapper<T>
where T : class
{
private static readonly ItemMapper[] __mappers;
static Mapper()
{
__mappers = typeof (T)
.GetProperties()
.Where( p => p.IsDefined( typeof (MappingAttribute), false ) )
.Select( p => new
{
Property = p,
Attribute = p
.GetCustomAttributes( typeof (MappingAttribute), false )
.Cast<MappingAttribute>()
.FirstOrDefault()
} )
.Select( m => new ItemMapper( m.Property, m.Attribute ) )
.ToArray();
}
public static void MapRow( T instance, DataRow row )
{
foreach ( var mapper in __mappers )
{
mapper.MapRow( instance, row );
}
}
#region Nested type: ItemMapper
private sealed class ItemMapper
{
private readonly MappingAttribute _attribute;
private readonly PropertyInfo _property;
public ItemMapper( PropertyInfo property, MappingAttribute attribute )
{
_property = property;
_attribute = attribute;
}
public void MapRow( T instance, DataRow rowInstance )
{
//TODO: Implement this with the code already provided
}
}
#endregion
}
#endregion
}
{
///
///根据定义的属性将DataRow对象映射到实体T。
///
///要映射的实体。
///DataRow实例。
///实例来创建实体。
公共静态T MapRow(此DataRow rowInstance),其中T:class,new()
{
//创建T项
var instance=newt();
Mapper.MapRow(实例,rowInstance);
返回实例;
}
#区域嵌套类型:映射器
私有静态类映射器
T:在哪里上课
{
私有静态只读项映射器[]\uu映射器;
静态映射器()
{
__映射器=类型(T)
.GetProperties()
.Where(p=>p.IsDefined(typeof(MappingAttribute),false))
.选择(p=>new
{
属性=p,
属性=p
.GetCustomAttributes(typeof(MappingAttribute),false)
.Cast()
.FirstOrDefault()
} )
.Select(m=>newitemmapper(m.Property,m.Attribute))
.ToArray();
}
公共静态void MapRow(T实例,DataRow)
{
foreach(映射器中的变量映射器)
{
mapper.MapRow(实例,行);
}
}
#区域嵌套类型:ItemMapper
私有密封类ItemMapper
{
私有只读映射属性_属性;
私有只读财产信息财产;
公共项目映射器(PropertyInfo属性,MappingAttribute属性)
{
_财产=财产;
_属性=属性;
}
public void MapRow(T实例,DataRow实例)
{
//TODO:使用已提供的代码实现此功能
}
}
#端区
}
#端区
}
第一次为给定的
调用扩展方法时,静态构造函数将为每个附加了MappingAttribute
的属性运行并缓存一个实例Mapper
。然后,对于此后的每个调用,它都将使用缓存的映射器进行实际复制
您还可以将Mapper
抽象化,并为setValue()
中的每个分支使用不同的子类。这样,大多数反射只发生一次。公共静态类DataRowExtensions
{
///
///根据定义的属性将DataRow对象映射到实体T。
///
///要映射的实体。
///DataRow实例。
///实例来创建实体。
公共静态T MapRow(此DataRow rowInstance),其中T:class,new()
{
//创建T项
var instance=newt();
Mapper.MapRow(实例,rowInstance);
返回实例;
}
#区域嵌套类型:映射器
私有静态类映射器
T:在哪里上课
{
私有静态只读项映射器[]\uu映射器;
静态映射器()
{
__映射器=类型(T)
.GetProperties()
.Where(p=>p.IsDefined(typeof(MappingAttribute),false))
.选择(p=>new
{
属性=p,
属性=p
.GetCustomAttributes(typeof(MappingAttribute),false)
.Cast()
.FirstOrDefault()
} )
.Select(m=>newitemmapper(m.Property,m.Attribute))
.ToArray();
}
公共静态void MapRow(T实例,DataRow)
{
foreach(映射器中的变量映射器)
{
mapper.MapRow(实例,行);
}
}
#区域嵌套类型:ItemMapper
私有密封类ItemMapper
{
私有只读映射属性_属性;
私有只读财产信息财产;
公共项目映射器(PropertyInfo属性,MappingAttribute属性)
{
_财产=财产;
_属性=属性;
}
public void MapRow(T实例,DataRow实例)
{
//TODO:使用已提供的代码实现此功能
}
}
#端区
}
#端区
}
第一次为给定的
调用扩展方法时,静态构造函数将为每个附加了MappingAttribute
的属性运行并缓存一个实例Mapper
。然后,对于此后的每个调用,它都将使用缓存的映射器进行实际复制
您还可以将
Mapper
抽象化,并为setValue()
中的每个分支使用不同的子类。这样,您的大多数反射只发生一次。瓶颈到底在哪里?您是否在构建地图后缓存它们?您可以将属性的索引映射到缓存的映射类型,这样就不必对连续调用使用反射。盯着探查器输出可能非常危险,很容易忽略数据库查询的成本。但这正是ORM工具流行的原因。Linq到Sql、实体框架、Hibernate等,他们计算
public sealed class MappingAttribute : Attribute
{
public string ColumnName { get; set; }
public object DefaultValue { get; set; }
public DbParametersTypes DBType { get; set; }
public bool IsKey { get; set; }
public string IdentifierFK { get; set; }
public bool IsParameter { get; set; }
public MappingAttribute(string columnName)
{
if (String.IsNullOrEmpty(columnName))
throw new ArgumentNullException("columnName");
ColumnName = columnName;
}
}
public static class DataRowExtensions
{
/// <summary>
/// Maps DataRow objecto to entity T depending on the defined attributes.
/// </summary>
/// <typeparam name="T">Entity to map.</typeparam>
/// <param name="rowInstance">DataRow instance.</param>
/// <returns>Instance to created entity.</returns>
public static T MapRow<T>( this DataRow rowInstance ) where T : class, new()
{
//Create T item
var instance = new T();
Mapper<T>.MapRow( instance, rowInstance );
return instance;
}
#region Nested type: Mapper
private static class Mapper<T>
where T : class
{
private static readonly ItemMapper[] __mappers;
static Mapper()
{
__mappers = typeof (T)
.GetProperties()
.Where( p => p.IsDefined( typeof (MappingAttribute), false ) )
.Select( p => new
{
Property = p,
Attribute = p
.GetCustomAttributes( typeof (MappingAttribute), false )
.Cast<MappingAttribute>()
.FirstOrDefault()
} )
.Select( m => new ItemMapper( m.Property, m.Attribute ) )
.ToArray();
}
public static void MapRow( T instance, DataRow row )
{
foreach ( var mapper in __mappers )
{
mapper.MapRow( instance, row );
}
}
#region Nested type: ItemMapper
private sealed class ItemMapper
{
private readonly MappingAttribute _attribute;
private readonly PropertyInfo _property;
public ItemMapper( PropertyInfo property, MappingAttribute attribute )
{
_property = property;
_attribute = attribute;
}
public void MapRow( T instance, DataRow rowInstance )
{
//TODO: Implement this with the code already provided
}
}
#endregion
}
#endregion
}