首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >System.Reflection性能

System.Reflection性能
EN

Stack Overflow用户
提问于 2014-03-20 12:09:16
回答 1查看 455关注 0票数 1

我有一个数据库管理器,用于插入或添加到内部SQLite数据库以及读取。

对于读回,我使用如下的泛型方法

代码语言:javascript
运行
复制
 public List<T> GetListOfObjects<T>(string id) where T:IIdentity, new()
    {
        lock (dbLock)
        {
            using (var sqlCon = new SQLiteConnection(DBPath))
            {
                sqlCon.Execute(Constants.DBClauseSyncOff);
                sqlCon.BeginTransaction();
                string sql = string.Format("SELECT * FROM {0} WHERE id=\"{1}\"", GetName(typeof(T).ToString()), id);
                var data = sqlCon.Query<T>(sql);
                return data;
            }
        }
    }

没什么了不起的,但我所有的读取方法大约有130行代码。

不过,我的策划人是不同的--差不多1500行,覆盖了一整堆的课程。我想做的是合理化使用系统反射的insert/update方法,不要担心要插入的类,而是允许反射为我做。

根据我所读到的,这是完全可能的,因此我应该能够将代码压缩成类似于

代码语言:javascript
运行
复制
public void InsertOrUpdateClass<T>(List<T> obj) : where T:IIdentity, new()
{
     foreach(var o in obj)
         InsertOrUpdateClass(o);
}

public void InsertOrUpdateClass<T>(T o) : where T:IIdentity, new()
{
     lock (dbLock)
        {
            using (var sqlcon = new SQLiteConnection(DBPath))
            {
                sqlcon.Execute(Constants.DBClauseSyncOff);
                sqlcon.BeginTransaction();
                try
                {
                    // use reflection to construct the SQLite command line, insert
                    // into a string and pass into the query
                   if (sqlcon.Execute(SQLquery) == 0)
                        sqlcon.Insert(o, typeof(T));
                    sqlcon.Commit(); 
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error in InsertOrUpdateClass : {0}", ex.Message);
                    sqlcon.Rollback();
                }
            }
        }

然而,根据我所读到的,使用反射来完成这一操作将使x5的性能比更标准的每个类插入或更新的单一方法的性能更好。我看到的大多数例子都表明,由于我没有使用任何讨厌的东西(比如Activator.Create.),我的方法应该和“标准”代码一样快

类(与数据库一样)具有不同的长度,并添加了忽略和PrimaryKey的数据参数。我还没有发现任何关于反射是否会在这两个问题上被混淆的问题。

如有任何建议,将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-03-20 13:18:11

一种使用表达式树的非常基本/天真的方法。根据对象的复杂性,您肯定需要在这方面做一些工作,但这应该是一个很好的起点:

代码语言:javascript
运行
复制
private readonly Dictionary<Type, Func<Object, String>> queryBuilders =
   new Dictionary<Type, Func<object, string>>();

public String GetInsertQuery(Object entity)
{
   var type = entity.GetType();
   if (!queryBuilders.ContainsKey(type))
   {
      var param = Expression.Parameter(typeof(Object), "entity");
      var typedObject = Expression.Variable(type, "obj");
      var stringBuilder = Expression.Variable(typeof (StringBuilder), "sb");

      var appendString = typeof (StringBuilder).GetMethod("Append", new[] {typeof (String)});
      var objectToString = typeof(Object).GetMethod("ToString");

      var code = new List<Expression>();
      code.Add(Expression.Assign(typedObject, Expression.Convert(param, type)));
      code.Add(Expression.Assign(stringBuilder, Expression.New(typeof (StringBuilder))));

      code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(string.Format("INSERT INTO {0} (", type.Name))));

      var properties = type.GetProperties();

      for (int i = 0; i < properties.Length - 1; i++)
      {
         code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(properties[i].Name)));
         code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(", ")));
      }

      code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(properties[properties.Length - 1].Name)));

      code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(") VALUES (")));

      for (int i = 0; i < properties.Length - 1; i++)
      {
         code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("'")));
         code.Add(Expression.Call(stringBuilder, appendString, Expression.Call(Expression.Property(typedObject, properties[i]), objectToString)));
         code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("', ")));
      }

      code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("'")));
      code.Add(Expression.Call(stringBuilder, appendString, Expression.Call(Expression.Property(typedObject, properties[properties.Length - 1]), objectToString)));
      code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant("', ")));

      code.Add(Expression.Call(stringBuilder, appendString, Expression.Constant(");")));


      code.Add(Expression.Call(stringBuilder, "ToString", new Type[] { }));

      var expression = Expression.Lambda<Func<Object, String>>(Expression.Block(new[] { typedObject, stringBuilder }, code), param);
      queryBuilders[type] = expression.Compile();
   }

   return queryBuilders[type](entity);
}

尽管这也使用反射,但主要的区别是反射只使用一次,并进一步调用每种对象类型使用编译过的代码,因此没有明显的性能影响。主要的缺点显然是复杂性--简单的方法,而不是傻瓜和通用的方法占用了相当多的代码行--您肯定需要考虑减少代码库(以及潜在地提高可维护性)的好处是否值得花费(这也是可维护性--但您有一个非常复杂的方法,而不是数以千计的方法)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22532571

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档