系统反射性能 - c#

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

为了回读,我使用了像这样的通用方法

 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行代码。

我的二传手虽然有所不同-几乎一千五百行涵盖了一大堆课程。我想做的是使用系统反射对插入/更新方法进行合理化处理,而不用担心要插入的类,但允许反射为我完成。

根据我的阅读,这是完全可能的,因此我应该能够将代码压缩为类似于此的内容

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 ...),因此我的方法应该与“标准”代码一样快

这些类(对于数据库而言)具有不同的长度,并添加了[Ignore]和[PrimaryKey]数据参数。如果对这两个问题感到困惑,我还没有发现任何问题。

任何建议,将不胜感激。

参考方案

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

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

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

当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java

我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…

改造正在返回一个空的响应主体 - java

我正在尝试使用Retrofit和Gson解析一些JSON。但是,我得到的响应机构是空的。当我尝试从对象中打印信息时,出现NullPointerException。我确保URL正确,并且我也确保POJO也正确。我正在使用jsonschema2pojo来帮助创建POJO类。这是我要解析的JSON{ "?xml": { "@versi…

每个文件合并后添加换行 - python

我有很多类似以下内容的JSON文件:例如。1.json{"name": "one", "description": "testDescription...", "comment": ""} test.json{"name"…

您如何在列表内部调用一个字符串位置? - python

我一直在做迷宫游戏。我首先决定制作一个迷你教程。游戏开发才刚刚开始,现在我正在尝试使其向上发展。我正在尝试更改PlayerAre变量,但是它不起作用。我试过放在列表内和列表外。maze = ["o","*","*","*","*","*",…

Mongo汇总 - javascript

我的收藏中有以下文件{ "_id": ObjectId("54490b8104f7142f22ecc97f"), "title": "Sample1", "slug": "samplenews", "cat": …