题记:写这篇博客要主是加深自己对反射方法的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢。
原文地址:http://www.codeproject.com/Articles/503527/Reflection-optimization-techniques
反射是 Microsoft .NET framework 中非常强大的特性,它在 System.Reflection 命名空间中供给了一整套在运行时动态载入/处理程序集的 API。
反射 (Reflection) 如此强大,但仍需谨慎应用,因为它实际上是一种用性能换扩展性的一种方法,这里供给了一些优化反射的方法,以期把对性能的影响最小化。
public void DynamicExecution() { Type objType = Type.GetType("DynamicExecution.Test.DynamicClass"); object obj = Activator.CreateInstance(objType); MethodInfo mInfo = objType.GetMethod("AddNumbers", new Type[] { typeof(int), typeof(int) }); // 动态调用 obj 对象上的 AddNumbers 方法 mInfo.Invoke(obj, new object[] { 1, 5 }); PropertyInfo pInfo = objType.GetProperty("TEST_ID"); // 动态设置 obj 对象的 ID 属性 pInfo.SetValue(obj, "TEST_ID", null ); }
Public void OptimizedDynamicExecution() { Type objType = Type.GetType("DynamicExecution.Test.DynamicClass"); IDynamicClass obj = Activator.CreateInstance(objType) as IDynamicClass; if (null != obj) { // 静态调用 obj 对象上的 AddNumbers 方法 int result = obj.AddNumbers(1, 5); // 静态设定 obj 对象的 ID 属性 obj.ID = 10; } } // 在 OptimizedDynamicExecution API 中应用的 Interface public interface IDynamicClass { int ID { get; set; } int AddNumbers(int a, int b); }
[Table(Name="Employees")] public class Employee : Entity { [PrimaryKey] public int Id { get; set; } public string Name { get; set; } public string Address { get; set; } public DateTime DOB { get; set; } } public class Entity { public Entity() { Type curType = this.GetType(); object[] tableAttributes = curType.GetCustomAttributes(typeof(TableAttribute), true); if(null != tableAttributes && tableAttributes.Count() > 0) { // Retrieve the attribute information } // Use the attribute information here } }
以上定义了一个 Employee 实体类,对应数据库中的表明为 “Employees”,另外它的 Id 属性标记了一个 PrimaryKey 属性。
为了获取这些定义在 custom attributes 中的信息,在父类中应用了反射。
// 追加一个 C# 结构来存储信息 public struct TableInfo { public string TableName; public string PrimaryKey; } public class Entity { private static Dictionary<Type, TableInfo> tableInfoList = new Dictionary<Type, TableInfo>(); public Entity() { Type curType = this.GetType(); TableInfo curTableInfo; if (!tableInfoList.TryGetValue(curType, out curTableInfo)) { lock (this) { // 应用两重检查来下降 lock 消耗 if (!tableInfoList.TryGetValue(curType, out curTableInfo)) { object[] tableAttributes = curType.GetCustomAttributes(typeof(TableAttribute), true); if(null != tableAttributes && tableAttributes.Count() > 0) { // 缓存中没有时,新建一个 TableInfo curTableInfo = new TableInfo(); curTableInfo.TableName = ((TableAttribute) tableAttributes[0]).Name; // 其他处理 //把新建的 TableInfo 参加缓存 tableInfoList.Add(curType, curTableInfo); } } } } // use curTableInfo here } }
这里没有对反射操作停止修改,而是通过对反射的信息停止缓存从而增加反射操作的次数来进步程序的执行效率
如今的程序都强调低耦合,允许在运行时动态载入配置文件中指定的程序集/模块,这平日都应用到反射并因此下降了运行效率。
Microsoft .NET 轻量级代码生成可以处理“创立设计时未知类型对象”的问题,它在 System.Reflection.Emit 命名空间下供给了多个 API。
这个技巧能增加反射的过度应用,并且通过缓存方法代理的方法来进步后续调用的执行效率。
// 依赖的协议接口 public interface ISecurityProvider { bool ValidateUser(string userId, string password); List<User> GetUsersList(); } // 依赖的具体实现类 public class DefaultSecurityProvider : ISecurityProvider { public bool ValidateUser(string userId, string password) { ... } public List<User> GetUsersIist() { ... } } // 动态实例化 DefaultSecuirtyProvider 的方法 private void CreateInstance() { Type classType = Type.GetType("DefaultSecurityProvider, AssemblyName"); // 应用反射动态创立一个实例对象 ISecurityProvider employeeInstance = Activator.CreateInstance(classType) as ISecurityProvider; }
// 动态创立实例(不应用反射) private void CreateInstance() { Type classType = Type.GetType("DefaultSecurityProvider, AssemblyName"); // 获取一个指定对象的实例化方法的代理 delegate CreateInstanceDelegate createInstance = ObjectInstantiater(classType); // 执行该代理来获取指定对象的一个实例 ISecurityProvider employeeInstance = createInstance() as ISecurityProvider; }
如果你想晓得的更多一些,可以参考以下代码(截取自 System.Reflection.Emit 命名空间)
// 实例方法的代理声明 public delegate object CreateInstanceDelegate(); // 缓存实例方法代理的 Dictionary private static Dictionary<Type, CreateInstanceDelegate> _createInstanceDelegateList = new Dictionary<Type, CreateInstanceDelegate>(); // 动态获取实例化指定类型的方法 public static CreateInstanceDelegate ObjectInstantiater(Type objectType) { CreateInstanceDelegate createInstanceDelegate; if (!_createInstanceDelegateList.TryGetValue(objectType, out createInstanceDelegate)) { lock (objectType) { if (!_createInstanceDelegateList.TryGetValue(objectType, createInstanceDelegate)) { // 建立一个新方法 DynamicMethod dynamicMethod = new DynamicMethod("Create_" + objectType.Name, objectType, new Type[0]); // 获取默认的构造函数 ConstructorInfo ctor = objectType.GetConstructor(new Type[0]); // 生成 IL 代码 ILGenerator ilgen = dynamicMethod.GetILGenerator(); ilgen.Emit(OpCodes.Newobj, ctor); ilgen.Emit(OpCodes.Ret); // 建立一个代理并缓存在 dictionary 中 createInstanceDelegate = (CreateInstanceDelegate)dynamicMethod .CreateDelegate(typeof(CreateInstanceDelegate)); _createInstanceDelegateList[objectType] = createInstanceDelegate; } } } return createInstanceDelegate; // 返回对象的实例化代理 }
绝大多数的 ORM Frameworks 中,实体类对应了数据库中的表,并通过反射来读取/设定实体类的各个属性,这非常影响性能。这可以鉴戒场景3的方法该改善,此处我们将应用.NET Frameworks 3.5 中包括的 Expression Trees 特性来实现。
// Employees 实体类 public class Employees { public int EmployeeID { get; set; } public string LastName { get; set; } public string FirstName { get; set; } public DateTime BirthDate { get; set; } } // Employees 列表,用来存放从 data reader 读取到的全部数据 List<Employees> empList = new List<Employees>(); using(SqlConnection con = new SqlConnection(@"......")) { SqlCommand cmd = new SqlCommand("Select * from employees"); cmd.Connection = con; con.Open(); // 调用 ReadList 把 data reader 查询出的信息存入实体类 using (SqlDataReader reader = cmd.ExecuteReader()) { empList = ReadList<Employees>(reader); } } // 把 data reader 查询出的信息转换成实体列表 public List<T> ReadList<T>(SqlDataReader reader) where T : new() { var list = new List<T>(); while (reader.Read()) { T entity = new T(); Type entityType = typeof(T); foreach(var entityProperty in entityType.GetProperties()) { // 应用反射来设定实体对象的每一个属性 entityProperty.SetValue(entity, reader[entityProperty.Name], null); } list.Add(entity); } return list; }
public List<T> ReadList<T>(SqlDataReader reader) { var list = new List<T>(); Func<SqlDataReader, T> readRow = GetReader<T>(); // 从 GetReader 函数获取一个代理,并通过该代理来创立对象 while (reader.Read()) { list.Add(readRow(reader)); } return list; } // 应用一个 ConcurrentDictionary 来缓存各类型的代理 ConcurrentDictionary<Type, Delegate> ExpressionCache = new ConcurrentDictionary<Type, Delegate>(); // 获取(并创立缓存)各类型的初始化 Expression Trees // PS:原文未供给该函数,所以翻译的时候自己写了下(简略调试通过),若有问题请联系我 public Func<SqlDataReader, T> GetReader<T>() { Delegate func; var entityType = typeof(T); if (!ExpressionCache.TryGetValue(entityType, out func)) { // lambda 输入参数 var readerParam = Expression.Parameter(typeof(SqlDataReader), "reader"); // lambda 处理 var assignmentExpressions = new List<MemberBinding>(); foreach (var entityProperty in entityType.GetProperties()) { var assignmentExpression = Expression.Bind( entityProperty.GetSetMethod(), Expression.Convert( Expression.Call( readerParam, typeof(SqlDataReader).GetMethod("get_Item", new[] { typeof(string) }), Expression.Constant(entityProperty.Name, typeof(string))), entityProperty.PropertyType)); assignmentExpressions.Add(assignmentExpression); } var bodyExporess = Expression.MemberInit(Expression.New(entityType), assignmentExpressions); var lambda = Expression.Lambda<Func<SqlDataReader, T>>(bodyExporess, new[] { readerParam }); func = lambda.Compile(); ExpressionCache.TryAdd(entityType, func); } return (Func<SqlDataReader, T>)func; }
文章结束给大家分享下程序员的一些笑话语录: 警告
有一个小伙子在一个办公大楼的门口抽着烟,一个妇女路过他身边,并对他 说, “你知道不知道这个东西会危害你的健康?我是说, 你有没有注意到香烟 盒上的那个警告(Warning)?”
小伙子说,“没事儿,我是一个程序员”。
那妇女说,“这又怎样?”
程序员说,“我们从来不关心 Warning,只关心 Error”
--------------------------------- 原创文章 By
反射和方法
---------------------------------