反射的性能问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射的性能问题相关的知识,希望对你有一定的参考价值。

我正在尝试动态搜索EF Core。我在这样的循环中完成了整个事情:

foreach (var i in vm.SearchProperties)
{
  if (result == null)
    result = db.MyTable.Where(x => x.GetType().GetProperty(i).GetValue(x, null).ToString().ToLower().StartsWith("MySearchString"));
  else
    result = result.Where(x => x.GetType().GetProperty(i).GetValue(x,null).ToString().ToLower().StartsWith(i.Suchfeld.ToLower(“mySearchString”)));
}

在我添加反射部分之前,它运行得非常快。一旦我将反射添加到它,它就减慢了1000倍。任何想法我如何得到它加速或反射部分周围。

答案

您的表达式太复杂,无法由LINQ to SQL转换器解释,因此它正在表中的每个项目上进行编译和执行,因此执行速度非常慢也就不足为奇了。

您需要根据要搜索的属性构建表达式树,然后构造一个Expression<Func<MyType, bool>>以传递给您的Where(...)方法。这样LINQ to SQL转换器就可以识别它。

试试这个:

ParameterExpression param = Expression.Parameter(typeof(MyType));
MethodInfo stringStartsWith = typeof(string).GetMethods().First(m => m.Name == "StartsWith" && m.GetParameters().Length == 1);

PropertyInfo firstProp = typeof(MyType).GetProperty(vm.SearchProperties.First());
MemberExpression firstMembAccess = Expression.Property(param, firstProp);
MethodCallExpression firstStartsWithExpr = Expression.Call(firstMembAccess, stringStartsWith, Expression.Constant(mySearchString));
Expression current = firstStartsWithExpr;

foreach (string s in vm.SearchProperties.Skip(1))
{
    PropertyInfo prop = typeof(MyType).GetProperty(s);
    MemberExpression membAccess = Expression.Property(param, prop);
    MethodCallExpression startsWithExpr = Expression.Call(membAccess, stringStartsWith, Expression.Constant(mySearchString));
    current = Expression.OrElse(current, startsWithExpr);
}

Expression<Func<MyType, bool>> mySearchExpression = Expression.Lambda<Func<MyType, bool>>(current, param);

result = db.MyTable.Where(mySearchExpression);

注意:MyType指的是您的实体类型。

另一答案

正如人们已经回答的那样,反射不能用于IQueryable。

数据加载到内存中并执行Where子句。

它类似于您完成以下代码(在where子句之前添加ToList()):

foreach (var i in vm.SearchProperties)
{
  if (result == null)
    result = db.MyTable.ToList().Where(x => x.GetType().GetProperty(i).GetValue(x, null).ToString().ToLower().StartsWith("MySearchString"));
  else
    result = result.ToList().Where(x => x.GetType().GetProperty(i).GetValue(x,null).ToString().ToLower().StartsWith(i.Suchfeld.ToLower(“mySearchString”)));
}

@Mr Anderson是对的。您需要使用表达式树而不是反射。

但是,使用表达式树有时可能构建起来非常复杂。

免责声明:我是Eval-Expression.NET项目的所有者

该项目允许您在运行时评估和执行动态表达式。

简而言之,您可以将动态字符串传递给where子句。

维基:Eval-Expression.NET - LINQ Dynamic

foreach (var i in vm.SearchProperties)
{
  if (result == null)
    result = db.MyTable.Where(x => "x." + i + ".ToLower().StartsWith('MySearchString')");
  else
    result = result.Where(x => "x." + i + ".ToLower().StartsWith('MySearchString')");
}

以上是关于反射的性能问题的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL片段着色器不照亮场景

为啥我的 Ray March 片段着色器反射纹理查找会减慢我的帧速率?

11.反射带来的性能问题

java反射的性能问题

JAVA反射会降低你的程序性能吗?

将 OpenGL 片段着色器设置为仅通过漫反射减少 vec4 色点的 RGB 值,而不是 alpha