简体   繁体   English

System.Reflection性能

[英]System.Reflection performance

I have a database manager for inserting or adding into an internal SQLite database as well as for reading. 我有一个数据库管理器,用于插入或添加到内部SQLite数据库以及读取。

For read back, I use a generic method such as this 为了回读,我使用诸如此类的通用方法

 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;
            }
        }
    }

Nothing amazing, but all of my read methods amount to roughly 130 lines of code. 没有什么了不起的,但我所有的阅读方法都相当于大约130行代码。

My setters though are different - almost 1500 lines covering a whole pile of classes. 我的主持人虽然不同 - 几乎有1500行覆盖了整堆课程。 What I would like to do is rationalise the insert/update methods using system reflection and to not worry about the class being inserted to, but allow reflection to do it for me. 我想要做的是使用系统反射合理化插入/更新方法,而不用担心要插入的类,但允许反射为我做。

From what I've read, this is entirely possible and I should therefore be able to compact the code to something akin to this 从我所读到的,这是完全可能的,因此我应该能够将代码压缩到类似于此的东西

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();
                }
            }
        }

However, from what I have read, using reflection to do this would give a performance hit of about x5 over the more standard single method per class for insert or update. 但是,根据我的阅读,使用反射来执行此操作会使每个类的更标准单个方法的插入或更新性能大约为x5。 Most of the examples I've seen suggest that as I'm not using anything nasty (like Activator.Create...), my method should be as fast as "standard" code 我见过的大多数例子都表明,由于我没有使用任何令人讨厌的东西(比如Activator.Create ......),我的方法应该和“标准”代码一样快

The classes (as they are for a database) have different lengths and have added data parameters of [Ignore] and [PrimaryKey]. 类(与数据库一样)具有不同的长度,并添加了[Ignore]和[PrimaryKey]的数据参数。 I've not found anything over if reflection would get confused over these two. 如果反思会对这两者产生混淆,我就没有发现任何结果。

Any advice would be appreciate on this. 任何建议都会对此表示赞赏。

A very basic/naive approach using expression trees. 使用表达式树的一种非常基本/天真的方法。 You would definitely need to do some work on this, depending on the complexity of your objects, but it should be a good starting point: 根据对象的复杂程度,你肯定需要做一些工作,但它应该是一个很好的起点:

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);
}

Although this uses reflection as well, the main difference is that reflection is used once and further calls for each object type use compiled code, so there's no significant performance hit. 虽然这也使用反射,但主要区别在于反射被使用一次,并且对每种对象类型的进一步调用使用编译代码,因此没有显着的性能损失。 The main drawback is obviously complexity - the simple approach, far from being fool-proof and universal took quite some lines of code - you definitely need to consider if the benefits of reducing the code base (and also potentially improving maintainability) is worth the cost (which is maintainability as well - but instead of thousands of methods, you have one which is quite complex). 主要的缺点是显而易见的复杂性 - 简单的方法,远远不是万无一失的,并且通用需要相当多的代码 - 您肯定需要考虑减少代码库(以及可能提高可维护性)的好处是否值得花费(这也是可维护性 - 但是有一种非常复杂的方法,而不是数千种方法)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM