You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LuExpressionUtils.cs 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using Luticate2.Auth.Utils.Dbo;
  7. using Luticate2.Auth.Utils.Dbo.Result;
  8. using Microsoft.CodeAnalysis.CSharp.Scripting;
  9. using Microsoft.CodeAnalysis.Scripting;
  10. namespace Luticate2.Auth.Utils.Business.Utils
  11. {
  12. public static class LuExpressionUtils
  13. {
  14. public class LuExpressionParserOptions
  15. {
  16. public ScriptOptions ScriptOptions { get; set; }
  17. }
  18. public static Expression GetFromConvert(Expression exp)
  19. {
  20. if (exp is LambdaExpression lambdaExpression)
  21. {
  22. return GetFromConvert(lambdaExpression);
  23. }
  24. if ((exp.NodeType == ExpressionType.Convert ||
  25. exp.NodeType == ExpressionType.ConvertChecked)
  26. && exp is UnaryExpression)
  27. {
  28. return ((UnaryExpression) exp).Operand;
  29. }
  30. else
  31. {
  32. return exp;
  33. }
  34. }
  35. public static LambdaExpression GetFromConvert(LambdaExpression exp)
  36. {
  37. var body = GetFromConvert(exp.Body);
  38. var lambda = Expression.Lambda(body, exp.Parameters);
  39. return lambda;
  40. }
  41. public static Expression<Func<TType1, TType3>> AddConvert<TType1, TType2, TType3>(Expression<Func<TType1, TType2>> exp)
  42. {
  43. var converted = Expression.Convert(exp.Body, typeof(TType3));
  44. var expLambda = Expression.Lambda<Func<TType1, TType3>>(converted, exp.Parameters);
  45. return expLambda;
  46. }
  47. public static LuResult<TProperty> SetValueFromExpression<TDbo, TProperty>(Expression<Func<TDbo, TProperty>> property,
  48. TDbo dstObj, TProperty value)
  49. {
  50. var memberInfo = GetSingleMemberFromExpression(property);
  51. if (memberInfo != null)
  52. {
  53. return SetValueFromMember(memberInfo, dstObj, value);
  54. }
  55. return LuResult<TProperty>.Error(LuStatus.InternalError.ToInt(), "Bad member expression");
  56. }
  57. public static LuResult<TProperty> SetValueFromMember<TDbo, TProperty>(MemberInfo memberInfo,
  58. TDbo dstObj, TProperty value)
  59. {
  60. switch (memberInfo.MemberType)
  61. {
  62. case MemberTypes.Field:
  63. ((FieldInfo) memberInfo).SetValue(dstObj, value);
  64. return LuResult<TProperty>.Ok(value);
  65. case MemberTypes.Property:
  66. ((PropertyInfo) memberInfo).SetValue(dstObj, value);
  67. return LuResult<TProperty>.Ok(value);
  68. default:
  69. return LuResult<TProperty>.Error(LuStatus.InternalError.ToInt(),
  70. $"Bad MemberType: {memberInfo.MemberType}");
  71. }
  72. }
  73. public static LuResult<TProperty> GetValueFromExpression<TDbo, TProperty>(Expression<Func<TDbo, TProperty>> property,
  74. TDbo dboTo)
  75. {
  76. var memberInfo = GetSingleMemberFromExpression(property);
  77. if (memberInfo != null)
  78. {
  79. TProperty value;
  80. switch (memberInfo.MemberType)
  81. {
  82. case MemberTypes.Field:
  83. value = (TProperty) ((FieldInfo) memberInfo).GetValue(dboTo);
  84. return LuResult<TProperty>.Ok(value);
  85. case MemberTypes.Property:
  86. value = (TProperty) ((PropertyInfo) memberInfo).GetValue(dboTo);
  87. return LuResult<TProperty>.Ok(value);
  88. default:
  89. return LuResult<TProperty>.Error(LuStatus.InternalError.ToInt(),
  90. $"Bad MemberType: {memberInfo.MemberType}");
  91. }
  92. }
  93. return LuResult<TProperty>.Error(LuStatus.InternalError.ToInt(), "Bad member expression");
  94. }
  95. public static MemberInfo GetSingleMemberFromExpression(LambdaExpression property)
  96. {
  97. if (GetFromConvert(property.Body) is MemberExpression memberExpression &&
  98. (memberExpression.Expression == property.Parameters.First() ||
  99. (memberExpression.Expression == null && memberExpression.Member.DeclaringType == property.Parameters.First().Type)))
  100. {
  101. return memberExpression.Member;
  102. }
  103. return null;
  104. }
  105. public static MethodInfo GetSingleMethodFromExpression(LambdaExpression method)
  106. {
  107. // TODO check if something like methodCallExpression.Method.DeclaringType == method.Parameters.First().Type is usefull/required (static/extension methods)
  108. if (GetFromConvert(method.Body) is MethodCallExpression methodCallExpression &&
  109. (methodCallExpression.Object == method.Parameters.First() || methodCallExpression.Object == null))
  110. {
  111. return methodCallExpression.Method;
  112. }
  113. return null;
  114. }
  115. private static bool GetMembersFromExpression<TTypeTo, TProperty>(
  116. Expression<Func<TTypeTo, TProperty>> property, IList<MemberInfo> memberInfos)
  117. {
  118. MemberExpression memberExpression;
  119. if ((property.Body.NodeType == ExpressionType.Convert ||
  120. property.Body.NodeType == ExpressionType.ConvertChecked)
  121. && property.Body is UnaryExpression)
  122. {
  123. memberExpression = ((UnaryExpression) property.Body).Operand as MemberExpression;
  124. }
  125. else
  126. {
  127. memberExpression = property.Body as MemberExpression;
  128. }
  129. if (memberExpression != null)
  130. {
  131. if (memberExpression.Expression == property.Parameters.First())
  132. {
  133. memberInfos.Add(memberExpression.Member);
  134. return true;
  135. }
  136. else if (memberExpression.Expression is MemberExpression)
  137. {
  138. var exp = Expression.Lambda<Func<TTypeTo, object>>(memberExpression.Expression, property.Parameters);
  139. var res = GetMembersFromExpression(exp, memberInfos);
  140. if (res)
  141. {
  142. memberInfos.Add(memberExpression.Member);
  143. }
  144. return res;
  145. }
  146. }
  147. return false;
  148. }
  149. public static IList<MemberInfo> GetMembersFromExpression<TTypeTo, TProperty>(Expression<Func<TTypeTo, TProperty>> property)
  150. {
  151. var list = new List<MemberInfo>();
  152. if (GetMembersFromExpression(property, list))
  153. {
  154. return list;
  155. }
  156. return null;
  157. }
  158. public static LuResult<Expression<Func<TArg, TResult>>> Parse<TArg, TResult>(string data, LuExpressionParserOptions options)
  159. {
  160. try
  161. {
  162. // var options = ScriptOptions.Default.AddReferences(typeof(LuFilterParser).Assembly, typeof(Expression<>).Assembly);
  163. var expr = CSharpScript.EvaluateAsync<Expression<Func<TArg, TResult>>>(data, options.ScriptOptions).Result;
  164. return LuResult<Expression<Func<TArg, TResult>>>.Ok(expr);
  165. }
  166. catch (Exception e)
  167. {
  168. return LuResult<Expression<Func<TArg, TResult>>>.Error(LuStatus.InputError.ToInt(), e, "Failed to parse expression");
  169. }
  170. }
  171. }
  172. }