多个表,不同的字段,一个业务他们处理逻辑相同
所以想用反射来减少点代码量,但是使用反射来获取值速度下降的厉害 ~ x5
async List<object> SelectValues<T>(IQueryable<T> queryable, string fieldName)
where T : class
{
var type = typeof(T);
var field = type.GetProperty(fieldName);
if (field == null) throw new ArgumentNullException(nameof(fieldName));
var get = (T a) => (double?) field.GetValue(a);
return queryable
.Select(t => new {
V = get(t) //非常慢
// V = t.field 速度正常
}).ToList();
}
有没有什么优化方案,或者不应该这么干?
1
leeg810312 2022-04-11 20:25:54 +08:00 via Android
在集合循环执行反射不合适,可以替换 fieldname 参数为 lambda 表达式参数
|
2
hackfly 2022-04-11 20:47:50 +08:00
定义一个泛型类,定义一个查询接口,每个表类派生,都实现各自查询接口,这样也多不了多少代码,就是多几个实力类
|
3
moen 2022-04-11 21:08:27 +08:00
GetProperty/GetValue 这一套下来慢是必然的。一种解决方案就是使用表达式树,生成一个获取 t.prop 的委托;第二种就是使用 Source Generator 把用到的 T 的所有属性的获取代码都生成出来,0 反射
|
4
killergun 2022-04-11 21:11:39 +08:00
你看看官方的集合扩展 Select 是怎么实现的,根本就不需要反射
|
5
userforg2021 2022-04-11 21:55:24 +08:00
你这个需求。。。不就是 Select 的功能吗。。。。
|
6
Rocketer 2022-04-11 23:09:07 +08:00
t.field 会被直接翻译成 sql 语句在数据库中执行,而反射只能把数据先取到内存中,转化成对象,再反射取值,当然慢。
更何况反射本身就慢。 你这个需求,可以使用 Dynamic LINQ 来替换 Select 里面的内容,从而使操作能最终变成 sql 语句。 官方例子就有: https://dynamic-linq.net/basic-simple-query |
7
beginor 2022-04-11 23:24:06 +08:00
这个只需要对 Linq 做一点儿扩展就够,就是构建简单的取属性的 lambda 表达式传进去就行了, 甚至都不需要第三方类库, 给你看一个动态添加排序的例子
https://github.com/beginor/appfx/blob/master/src/Core/LinqExtensions.cs#L64 |
8
ShareDuck 2022-04-12 09:04:04 +08:00
调用的时候,同样都要输入 fieldName ,也没有降低代码量吧。
|
9
coder001 2022-04-12 09:22:02 +08:00
在 IQueryable<T>用 AutoMapper 的 Projection 方法,可以生成查询表达式实现按需 Select
|
10
yuhangch OP @leeg810312
@hackfly @moen @killergun @userforg2021 @Rocketer @beginor 感谢各位,先用 dynamic linq 顶一下,后面有时间了再看看表达式树的方法 (头天晚上焦头烂额,发个帖第二天早上解决了,v 站 up |