Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

LuExpressionConverterVisitor.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using Luticate2.Auth.Utils.Business.Converters;
  6. using Luticate2.Auth.Utils.Business.Utils;
  7. using Luticate2.Auth.Utils.Dbo;
  8. using Luticate2.Auth.Utils.Dbo.Result;
  9. using Luticate2.Auth.Utils.Exceptions;
  10. using Luticate2.Auth.Utils.Interfaces;
  11. namespace Luticate2.Auth.Utils.Business.ExpressionConverter
  12. {
  13. public class LuExpressionConverterVisitor : ExpressionVisitor
  14. {
  15. public LuConvertersOptions Options { get; }
  16. protected IServiceProvider ServiceProvider { get; }
  17. public LuExpressionConverterVisitor(LuConvertersOptions options, IServiceProvider serviceProvider)
  18. {
  19. Options = options;
  20. ServiceProvider = serviceProvider;
  21. }
  22. protected LuResult<Stack<Expression>> StackSimpleExpression(Expression expression, Stack<Expression> stack)
  23. {
  24. stack.Push(expression);
  25. if (expression is MemberExpression memberExpression)
  26. {
  27. if (memberExpression.Expression != null)
  28. {
  29. var result = StackSimpleExpression(memberExpression.Expression, stack);
  30. return result;
  31. }
  32. return LuResult<Stack<Expression>>.Ok(stack);
  33. }
  34. else if (expression is MethodCallExpression methodCallExpression)
  35. {
  36. if (methodCallExpression.Object != null)
  37. {
  38. var result = StackSimpleExpression(methodCallExpression.Object, stack);
  39. return result;
  40. }
  41. return LuResult<Stack<Expression>>.Ok(stack);
  42. }
  43. else
  44. {
  45. return LuResult<Stack<Expression>>.Ok(stack);
  46. }
  47. }
  48. protected ILuObjectConverterDescriptor GetConverterDescriptor(Type typeFrom, Type typeTo)
  49. {
  50. var type = typeof(ILuObjectConverterDescriptor<,>);
  51. var gtype = type.MakeGenericType(typeFrom, typeTo);
  52. var descriptor = (ILuObjectConverterDescriptor) ServiceProvider.GetService(gtype);
  53. if (descriptor == null && typeFrom == typeTo)
  54. {
  55. descriptor = (ILuObjectConverterDescriptor) ServiceProvider.GetService(typeof(ILuObjectConverterDescriptorIdentity));
  56. }
  57. return descriptor;
  58. }
  59. protected LuResult<Expression> ConvertMemberExpression(MemberExpression memberExpression, Expression newExpression, Type typeTo)
  60. {
  61. var typeFrom = memberExpression.Expression == null ? memberExpression.Member.DeclaringType : memberExpression.Expression.Type;
  62. var descriptor = GetConverterDescriptor(typeFrom, typeTo);
  63. if (descriptor == null)
  64. {
  65. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  66. $"Could not find converter descriptor for {typeFrom} => {typeTo}");
  67. }
  68. var valueExpression = descriptor.GetMemberValueExpression(memberExpression.Member, Options);
  69. if (valueExpression == null)
  70. {
  71. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  72. $"Could not find converter descriptor lambda for {typeFrom} => {typeTo} => {memberExpression.Member}");
  73. }
  74. if (valueExpression.Parameters[0].Type != typeTo)
  75. {
  76. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  77. $"Invalid conversion lambda for {typeFrom} => {typeTo}");
  78. }
  79. if (newExpression != null)
  80. {
  81. Options.Parameters.Add(valueExpression.Parameters[0], newExpression);
  82. }
  83. var visitor = new LuExpressionParamReplaceVisitor(Options);
  84. newExpression = visitor.Visit(valueExpression.Body);
  85. if (newExpression != null)
  86. {
  87. Options.Parameters.Remove(valueExpression.Parameters[0]);
  88. }
  89. return LuResult<Expression>.Ok(newExpression);
  90. }
  91. protected LuResult<Expression> ConvertMethodCallExpression(MethodCallExpression methodCallExpression, Expression newExpression, Type typeTo)
  92. {
  93. var typeFrom = methodCallExpression.Object == null ? methodCallExpression.Method.DeclaringType : methodCallExpression.Object.Type;
  94. var descriptor = GetConverterDescriptor(typeFrom, typeTo);
  95. if (descriptor == null)
  96. {
  97. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  98. $"Could not find converter descriptor for {typeFrom} => {typeTo}");
  99. }
  100. var valueExpression = descriptor.GetMethodValueExpression(methodCallExpression.Method, Options);
  101. if (valueExpression == null)
  102. {
  103. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  104. $"Could not find converter descriptor lambda for {typeFrom} => {typeTo} => {methodCallExpression.Method}");
  105. }
  106. if (valueExpression.Parameters.Count != methodCallExpression.Arguments.Count + 1)
  107. {
  108. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  109. $"Converter descriptor lambda has incorrect number of arguments for {typeFrom} => {typeTo} => {methodCallExpression.Method}");
  110. }
  111. if (valueExpression.Parameters[0].Type != typeTo)
  112. {
  113. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  114. $"Invalid conversion lambda for {typeFrom} => {typeTo}");
  115. }
  116. var visitorConverter = new LuExpressionConverterVisitor(Options, ServiceProvider);
  117. for (var i = 0; i < methodCallExpression.Arguments.Count; ++i)
  118. {
  119. var convertedArgument = visitorConverter.Visit(methodCallExpression.Arguments[i]);
  120. Options.Parameters.Add(valueExpression.Parameters[i + 1], convertedArgument);
  121. }
  122. Options.Parameters.Add(valueExpression.Parameters[0], newExpression);
  123. var visitor = new LuExpressionParamReplaceVisitor(Options);
  124. newExpression = visitor.Visit(valueExpression.Body);
  125. Options.Parameters.Remove(valueExpression.Parameters[0]);
  126. return LuResult<Expression>.Ok(newExpression);
  127. }
  128. protected LuResult<Expression> ReplaceExpression(Expression expression)
  129. {
  130. var stackResult = StackSimpleExpression(expression, new Stack<Expression>());
  131. if (!stackResult)
  132. {
  133. return stackResult.To<Expression>();
  134. }
  135. Expression newExpression;
  136. var currentExp = stackResult.Data.Pop();
  137. if (currentExp is ParameterExpression parameterExpression)
  138. {
  139. if (!Options.Parameters.ContainsKey(parameterExpression))
  140. {
  141. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  142. $"Could not find a conversion for parameter {parameterExpression}");
  143. }
  144. newExpression = Options.Parameters[parameterExpression];
  145. }
  146. else if (currentExp is MemberExpression memberExpression)
  147. {
  148. var typeFrom = memberExpression.Member.DeclaringType;
  149. var typeTo = Options.TypeConverter.ConvertType(typeFrom);
  150. var convertResult = ConvertMemberExpression(memberExpression, null, typeTo);
  151. if (!convertResult)
  152. {
  153. return convertResult;
  154. }
  155. newExpression = convertResult.Data;
  156. }
  157. else if (currentExp is MethodCallExpression methodCallExpression)
  158. {
  159. var typeFrom = methodCallExpression.Method.DeclaringType;
  160. var typeTo = Options.TypeConverter.ConvertType(typeFrom);
  161. var convertResult = ConvertMethodCallExpression(methodCallExpression, null, typeTo);
  162. if (!convertResult)
  163. {
  164. return convertResult;
  165. }
  166. newExpression = convertResult.Data;
  167. }
  168. else
  169. {
  170. var visitor = new LuExpressionConverterVisitor(Options, ServiceProvider);
  171. newExpression = visitor.Visit(currentExp);
  172. }
  173. if (newExpression == null)
  174. {
  175. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  176. $"Invalid simple expression first member: {currentExp}", "");
  177. }
  178. while (stackResult.Data.Any())
  179. {
  180. currentExp = stackResult.Data.Pop();
  181. if (currentExp is MemberExpression memberExpression)
  182. {
  183. var typeTo = newExpression.Type;
  184. var convertResult = ConvertMemberExpression(memberExpression, newExpression, typeTo);
  185. if (!convertResult)
  186. {
  187. return convertResult;
  188. }
  189. newExpression = convertResult.Data;
  190. }
  191. else if (currentExp is MethodCallExpression methodCallExpression)
  192. {
  193. var typeTo = newExpression.Type;
  194. var convertResult = ConvertMethodCallExpression(methodCallExpression, newExpression, typeTo);
  195. if (!convertResult)
  196. {
  197. return convertResult;
  198. }
  199. newExpression = convertResult.Data;
  200. }
  201. else
  202. {
  203. return LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  204. $"Unknown expression type (should not happen) {currentExp}");
  205. }
  206. }
  207. return LuResult<Expression>.Ok(newExpression);
  208. }
  209. protected override Expression VisitMember(MemberExpression node)
  210. {
  211. return ReplaceExpression(node).ThrowIfNotSuccess().Data;
  212. }
  213. protected override Expression VisitMethodCall(MethodCallExpression node)
  214. {
  215. return ReplaceExpression(node).ThrowIfNotSuccess().Data;
  216. }
  217. protected override Expression VisitParameter(ParameterExpression node)
  218. {
  219. if (!Options.Parameters.ContainsKey(node))
  220. {
  221. LuResult<Expression>.Error(LuStatus.InternalError.ToInt(),
  222. $"Could not find a conversion for parameter {node}").Throw();
  223. }
  224. return Options.Parameters[node];
  225. }
  226. protected override Expression VisitLambda<T>(Expression<T> node)
  227. {
  228. var convertedParams = new List<ParameterExpression>();
  229. foreach (var parameter in node.Parameters)
  230. {
  231. var convertedParam = Expression.Parameter(Options.TypeConverter.ConvertType(parameter.Type));
  232. Options.Parameters.Add(parameter, convertedParam);
  233. convertedParams.Add(convertedParam);
  234. }
  235. var convertedBody = Visit(node.Body);
  236. foreach (var parameter in node.Parameters)
  237. {
  238. Options.Parameters.Remove(parameter);
  239. }
  240. var convertedLambda = Expression.Lambda(convertedBody, convertedParams);
  241. return convertedLambda;
  242. }
  243. }
  244. }