using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Luticate2.Auth.Utils.Business.Converters; using Luticate2.Auth.Utils.Business.ExpressionConverter; using Luticate2.Auth.Utils.Business.Utils; using Luticate2.Auth.Utils.Interfaces; namespace Luticate2.Auth.Utils.Business.ObjectConverterDescriptor { public class LuObjectConverterDescriptor : ILuObjectConverterDescriptor { protected class LuObjectConverterDescriptorMemberInfo { public LambdaExpression ValueExpression { get; set; } } protected class LuObjectConverterDescriptorMethodInfo { public LambdaExpression ValueExpression { get; set; } } protected delegate LuObjectConverterDescriptorMethodInfo DynamicMethodConverter(MethodInfo methodInfo, ILuConvertersTypeConverter typeConverter); private IDictionary StaticMemberConverters { get; } = new Dictionary(); private IDictionary StaticMethodConverters { get; } = new Dictionary(); private IDictionary DynamicMethodConverters { get; } = new Dictionary(); protected void AddMemberConverter(LambdaExpression memberFrom, LambdaExpression valueExpression) { // TODO: check memberInfo != null var memberInfo = LuExpressionUtils.GetSingleMemberFromExpression(memberFrom); StaticMemberConverters.Add(memberInfo, new LuObjectConverterDescriptorMemberInfo { ValueExpression = LuExpressionUtils.GetFromConvert(valueExpression) }); } protected void AddStaticMethodConverter(LambdaExpression methodFrom, LambdaExpression valueExpression) { // TODO: check methodInfo != null var methodInfo = LuExpressionUtils.GetSingleMethodFromExpression(methodFrom); StaticMethodConverters.Add(methodInfo, new LuObjectConverterDescriptorMethodInfo { ValueExpression = LuExpressionUtils.GetFromConvert(valueExpression) }); } protected void AddDynamicMethodConverter(LambdaExpression methodFrom, DynamicMethodConverter converter) { // TODO: check methodInfo != null var methodInfo = LuExpressionUtils.GetSingleMethodFromExpression(methodFrom); var genericMethodInfo = methodInfo.GetGenericMethodDefinition(); DynamicMethodConverters.Add(genericMethodInfo, converter); } protected void AddDynamicMethodConverterTemplate(LambdaExpression methodFrom) { AddDynamicMethodConverter(methodFrom, (info, converter) => { var genericMethodInfo = info.GetGenericMethodDefinition(); var templateMethodInfo = genericMethodInfo.MakeGenericMethod(info.GetGenericArguments().Select(converter.ConvertType).ToArray()); var lambdaParams = new List { Expression.Parameter(templateMethodInfo.DeclaringType) // TODO what if DeclaringType is static class }; var methodParams = templateMethodInfo.GetParameters().Select(x => Expression.Parameter(x.ParameterType)).ToList(); lambdaParams.AddRange(methodParams); var methodCallExpression = Expression.Call(templateMethodInfo.IsStatic ? null : lambdaParams[0], templateMethodInfo, methodParams); var body = LuExpressionUtils.GetFromConvert(methodCallExpression); var lambda = Expression.Lambda(body, lambdaParams); return new LuObjectConverterDescriptorMethodInfo { ValueExpression = lambda }; } ); } public LambdaExpression GetMemberValueExpression(MemberInfo memberInfo, LuConvertersOptions options) { if (StaticMemberConverters.ContainsKey(memberInfo)) { return StaticMemberConverters[memberInfo].ValueExpression; } return null; } public LambdaExpression GetMethodValueExpression(MethodInfo methodInfo, LuConvertersOptions options) { if (StaticMethodConverters.ContainsKey(methodInfo)) { return StaticMethodConverters[methodInfo].ValueExpression; } var genericMethodInfo = methodInfo.GetGenericMethodDefinition(); if (DynamicMethodConverters.ContainsKey(genericMethodInfo)) { var result = DynamicMethodConverters[genericMethodInfo](methodInfo, options.TypeConverter); if (result != null) { return result.ValueExpression; } } return null; } } public class LuObjectConverterDescriptor : LuObjectConverterDescriptor, ILuObjectConverterDescriptor { protected void AddMemberConverter(Expression> memberFrom, Expression> valueExpression) { AddMemberConverter((LambdaExpression) memberFrom, valueExpression); } protected void AddNullMemberConverter(Expression> memberFrom) { AddMemberConverter(memberFrom, to => null); } } }