ni":
//不属于(不是候选值列表之一)
321 e =
Expression.Not(BuildContainsExpression(rule, l, pt));
322 break;
323 case "nu":
//为空
324 r = Expression.Constant(
null);
325 e =
Expression.Equal(l, r);
326 break;
327 case "nn":
//不为空
328 r = Expression.Constant(
null);
329 e =
Expression.Not(Expression.Equal(l, r));
330 break;
331 case "bt":
//区间
332 throw new NotImplementedException($
"尚未实现创建{rule.Op}类型的比较表达式");
333 default:
334 throw new InvalidOperationException($
"不支持创建{rule.Op}类型的比较表达式");
335 }
336
337 return e;
338
339 static Expression BuildConstantExpression<TValue>(JqGridSearchRule jRule, Func<
string, TValue>
valueConvertor)
340 {
341 var rv =
valueConvertor(jRule.Data);
342 return Expression.Constant(rv);
343 }
344 }
345
346 /// <summary>
347 /// 构造Contains调用表达式
348 /// </summary>
349 /// <param name="rule">条件</param>
350 /// <param name="parameter">参数</param>
351 /// <param name="parameterType">参数类型</param>
352 /// <returns>Contains调用表达式</returns>
353 private static Expression BuildContainsExpression(JqGridSearchRule rule, Expression parameter, Type parameterType)
354 {
355 Expression e =
null;
356
357 var genMethod =
typeof(Queryable).GetMethods()
358 .Single(m => m.Name == nameof(Queryable.Contains) && m.GetParameters().Length ==
2);
359
360 var jsonArray = JsonSerializer.Deserialize<
string[]>
(rule.Data);
361
362 switch (parameterType)
363 {
364 #region 文字
365
366 case Type ct when ct ==
typeof(
char):
367 if (jsonArray.Any(o => o.Length !=
1)) {
throw new InvalidOperationException(
"字符型的候选列表中存在错误的候选项");}
368 e = CallContains(parameter, jsonArray, str => str[
0], genMethod, ct);
369 break;
370 case Type ct when ct ==
typeof(
string):
371 e = CallContains(parameter, jsonArray, str =>
str, genMethod, ct);
372 break;
373
374 #endregion
375
376 #region 有符号整数
377
378 case Type ct when ct ==
typeof(
sbyte):
379 e = CallContains(parameter, jsonArray,
sbyte.Parse, genMethod, ct);
380 break;
381 case Type ct when ct ==
typeof(
short):
382 e = CallContains(parameter, jsonArray,
short.Parse, genMethod, ct);
383 break;
384 case Type ct when ct ==
typeof(
int):
385 e = CallContains(parameter, jsonArray,
int.Parse, genMethod, ct);
386 break;
387 case Type ct when ct ==
typeof(
long):
388 e = CallContains(parameter, jsonArray,
long.Parse, genMethod, ct);
389 break;
390
391 #endregion
392
393 #region 无符号整数
394
395 case Type ct when ct ==
typeof(
byte):
396 e = CallContains(parameter, jsonArray,
byte.Parse, genMethod, ct);
397 break;
398 case Type ct when ct ==
typeof(
ushort):
399 e = CallContains(parameter, jsonArray,
ushort.Parse, genMethod, ct);
400 break;
401 case Type ct when ct ==
typeof(
uint):
402 e = CallContains(parameter, jsonArray,
uint.Parse, genMethod, ct);
403 break;
404 case Type ct when ct ==
typeof(
ulong):
405 e = CallContains(parameter, jsonArray,
ulong.Parse, genMethod, ct);
406 break;
407
408 #endregion
409
410 #region 小数
411
412 case Type ct when ct ==
typeof(
float):
413 e = CallContains(parameter, jsonArray,
float.Parse, genMethod, ct);
414 break;
415 case Type ct when ct ==
typeof(
double):
416 e = CallContains(parameter, jsonArray,
double.Parse, genMethod, ct);
417 break;
418 case Type ct when ct ==
typeof(
decimal):
419 e = CallContains(parameter, jsonArray,
decimal.Parse, genMethod, ct);
420 break;
421
422 #endregion
423
424 #region 其它常用类型
425
426 case Type ct when ct ==
typeof(DateTime):
427 e =
CallContains(parameter, jsonArray, DateTime.Parse, genMethod, ct);
428 break;
429 case Type ct when ct ==
typeof(DateTimeOffset):
430 e =
CallContains(parameter, jsonArray, DateTimeOffset.Parse, genMethod, ct);
431 break;
432 case Type ct when ct ==
typeof(Guid):
433 e =
CallContains(parameter, jsonArray, Guid.Parse, genMethod, ct);
434 break;
435 case Type ct when ct.IsEnum:
436 e = CallContains(Expression.Convert(parameter,
typeof(
object)), jsonArray, enumString =>
enumString.ToEnumObject(ct), genMethod, ct);
437 break;
438
439 #endregion
440 }
441
442 return e;
443
444 static MethodCallExpression CallContains<T>(Expression pa,
string[] jArray, Func<
string, T>
selector, MethodInfo genericMethod, Type type)
445 {
446 var data =
jArray.Select(selector).ToArray().AsQueryable();
447 var method =
genericMethod.MakeGenericMethod(type);
448
449 return Expression.Call(
null, method,
new[] { Expression.Constant(data), pa });
450 }
451 }
452 }
复制代码
1 public async Task<IActionResult> OnGetUserListAsync([FromQuery]JqGridParameter jqGridParameter)
2 {
3 var usersQuery = _userManager.Users.AsNoTracking();
4 if (jqGridParameter._search == "true")
5 {
6 usersQuery = usersQuery.Where(BuildWhere<ApplicationUser>(jqGridParameter.FilterObject, null));
7 }
8
9 var users = usersQuery.Include(u => u.UserRoles).ThenInclude(ur => ur.Role).OrderBy(u => u.InsertOrder)
10 .Skip((jqGridParameter.Page - 1) * jqGridParameter.Rows).Take(jqGridParameter.Rows).ToList();
11 var userCount = usersQuery.Count();
12 var pageCount = Ceiling((double) userCount / jqGridParameter.Rows);
13 return new JsonResult(
14 new
15 {
16 rows //数据集合
17 = users.Select(u => new
18 {
19 u.UserName,
20 u.Gender,
21 u.Email,
22 u.PhoneNumber,
23 u.EmailConfirmed,
24 u.PhoneNumberConfirmed,
25 u.CreationTime,
26 u.CreatorId,
27 u.Active,
28 u.LastModificationTime,
29 u.LastModifierId,
30 u.InsertOrder,
31 u.ConcurrencyStamp,
32 //以下为JqGrid中必须的字段
33 u.Id //记录的唯一标识,可在插件中配置为其它字段,但是必须能作为记录的唯一标识用,不能重复
34 }),
35 total = pageCount, //总页数
36 page = jqGridParameter.Page, //当前页码
37 records = userCount //总记录数
38 }
39 );
40 }
通过这次实践,深入了解了很多表达式树的相关知识,表达式树在编译流程中还算是高级结构了,耐点心还是能看懂,IL 才是真的晕,比原生汇编也好不到哪里去。C# 确实很有意思,入门简单,内部却深邃无比,在小白和大神手上完全是两种语言。Java 在 Java 8 时增加了 Stream 和 Lambda 表达式功能,一看就是在对标 Linq,不过那名字取的真是一言难尽,看代码写代码感觉如鲠在喉,相当不爽。由于 Stream 体系缺少表达式树,这种动态构造查询表达式的功能从一开始就不可能支持。再加上 Java 没有匿名类型,没有对象初始化器,每次用 Stream 就难受的一批,中间过程的数据结构也要专门写类,每个中间类还要独占一个文件,简直晕死。抄都抄不及格!
C# 引入 var 关键字核心是为匿名类型服务,毕竟是编译器自动生成的类型,写代码的时候根本没有名字,不用 var 用什么?简化变量初始化代码只是顺带的。结果 Java 又抄一半,还是最不打紧的一半,简化变量初始化代码。真不知道搞 Java 的那帮人在想些什么。