c# - C# 表达式树:对象数组到 Expression.New() 参数
问题描述
我想使用表达式树来提高一些对象关系映射代码的性能。旧代码如下所示:
public List<T> SqlToResults<T>(string query)
{
// Do SQL stuff, get matching constructor for type T ...
// ...
List<T> results = new List<T>();
// Create buffer for constructor parameters
object[] constructorParams = new object[reader.FieldCount];
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
// simplefied (there'd be some mapping to match correct order of parameters)
constructorParams[i] = reader[i];
}
// create new instance of T with our data
T result = (T)constructorInfoOfT.Invoke(constructorParams);
// add new result to list of results
results.Add(result);
}
return results;
}
上面代码中的性能瓶颈是ConstructorInfo.Invoke()
我想用表达式树替换的调用和与此答案Expression.New()
中的代码类似的调用。但是在编译时我不知道参数的数量及其类型,这似乎有点复杂。将一个表达式数组作为构造函数的参数,但我只有一个对象数组(这将是一个)。所以我必须以某种方式遍历 to 的内容,然后将每个元素映射到它自己的,然后可以作为to传递。Expression.New()
ParameterExpression
ParameterExpression
Expression
Expression[]
Expression.New()
我想到的代码看起来像这样:
internal delegate TInstance Constructor<TInstance>(object[] parameters);
internal Constructor<T> BuildConstructorFrom<T>(ConstructorInfo constructorInfo)
{
ParameterExpression constructorParameters = Expression.Parameter(typeof(object[]));
Expression[] parameterExpressions;
// ???
// somehow map entries in constructorParameters to entries in parameterExpressions
// ???
NewExpression constructorCall = Expression.New(constructorInfo, parameterExpressions);
Constructor<T> ctor = (Constructor<T>)Expression.Lambda<Constructor<T>>(constructorCall, constructorParameters).Compile();
return ctor;
}
我已经查看了类似的问题,例如使用表达式树的 foreach 循环和构建动态表达式树时的问题,但我仍然不确定如何在我的用例中使用这些循环。
解决方案
我设法弄清楚了。解决方案是使用Expression.ArrayIndex
传统的 for 循环:
internal Constructor<T> BuildConstructerFrom<T>(ConstructorInfo constructorInfo)
{
ParameterExpression constructorParameters = Expression.Parameter(typeof(object?[]));
ParameterInfo[] parametersInfos = constructorInfo.GetParameters();
Expression[] parameterExpressions = new Expression[parametersInfos.Length];
for (int i = 0; i < parametersInfos.Length; i++)
{
ConstantExpression ithIndex = Expression.Constant(i);
BinaryExpression ithParameter = Expression.ArrayIndex(constructorParameters, ithIndex);
UnaryExpression unboxedIthParameter = Expression.Convert(ithParameter, parametersInfos[i].ParameterType);
parameterExpressions[i] = unboxedIthParameter;
}
NewExpression constructorCall = Expression.New(constructorInfo, parameterExpressions);
Constructor<T> ctor = (Constructor<T>)Expression.Lambda<Constructor<T>>(constructorCall, constructorParameters).Compile();
return ctor;
}
推荐阅读
- android - Git 和 Android Studio 的奇怪行为
- azure-devops - Azure Devops - 为每个部署环境创建一个映射变量
- docker - 如何在 OpenJ9/Alpine 容器上使用 JProfiler 12.0.3 设置远程分析
- java - Java随机名称生成器,选择单词的长度
- android - 使用 Android 导航组件隐藏抽屉项目
- testing - 如何在 SAP Web IDE 中使用模拟数据开始测试?
- c# - 如何在 Anglesharp 中检测 dom 元素的变化
- php - 从 Laravel Eloquent 中的 Db 列获取特定值
- database - 基于项目的角色的数据库设计
- google-app-engine - 此页面加载延迟的原因可能是什么?