private Expression GetMemberAssignment(ReferenceMapperContext context, ParameterExpression subParam, MemberInfo memberInfo, Configuration MapperConfiguration) { var propertyInfo = (PropertyInfo)memberInfo; if (propertyInfo.PropertyType.IsBuiltIn(true)) { var conversion = MapperConfiguration[typeof(SimpleParam), propertyInfo.PropertyType].MappingExpression; var setter = memberInfo.GetSetterExp(); return(base.GetSimpleMemberExpressionInternal(conversion, context.TargetInstance, Expression.Convert(subParam, typeof(SimpleParam)), setter)); } else { PropertyInfo sourcemappingtype = null; Expression sourceValueExp = null; if (context.SourceInstance.Type == typeof(ComplexParam)) { sourcemappingtype = typeof(ComplexParam).GetProperty(nameof(ComplexParam.SubParams)); sourceValueExp = Expression.Property(Expression.Convert(subParam, typeof(ComplexParam)), nameof(ComplexParam.SubParams)); } if (propertyInfo.PropertyType.IsEnumerable()) { sourcemappingtype = typeof(ArrayParam).GetProperty(nameof(ArrayParam.Items)); sourceValueExp = Expression.Property(Expression.Convert(subParam, typeof(ArrayParam)), nameof(ArrayParam.Items)); } var targetsetprop = context.TargetInstance.Type.GetProperty(memberInfo.Name); var mappingSource = new MappingSource(sourcemappingtype); var mappingTarget = new MappingTarget(targetsetprop); var typeMapping = new TypeMapping(MapperConfiguration, propertyInfo.PropertyType, targetsetprop.PropertyType); var membermapping = new MemberMapping(typeMapping, mappingSource, mappingTarget); var membermappingcontext = new MemberMappingContext(membermapping); var targetProperty = Expression.Property(context.TargetInstance, memberInfo.Name); var guessedSourceType = typeof(ComplexParam); if (targetProperty.Type.IsBuiltIn(true)) { guessedSourceType = typeof(SimpleParam); } else if (targetProperty.Type.IsEnumerable()) { guessedSourceType = typeof(ArrayParam); } var targetType = targetProperty.Type; if (targetProperty.Type.IsInterface || targetProperty.Type.IsAbstract) { targetType = typeof(List <>).MakeGenericType(targetType.GetGenericArguments()); } var mapping = MapperConfiguration[targetType, targetsetprop.PropertyType]; var memberAssignment = ((ReferenceMapper)mapping.Mapper).GetMemberAssignment(membermappingcontext) .ReplaceParameter(membermappingcontext.SourceMember, "sourceValue") .ReplaceParameter(targetProperty, "targetValue") .ReplaceParameter(context.TargetInstance, "instance"); var mapping2 = MapperConfiguration[guessedSourceType, targetProperty.Type]; if (MapperConfiguration.IsReferenceTrackingEnabled) { return(ReferenceTrackingExpression.GetMappingExpression( context.ReferenceTracker, subParam, targetProperty, memberAssignment, context.Mapper, _mapper, Expression.Constant(mapping2, typeof(IMapping)))); } else { var mapMethod = ReferenceMapperContext.RecursiveMapMethodInfo .MakeGenericMethod(subParam.Type, targetProperty.Type); return(Expression.Block ( new[] { membermappingcontext.SourceMember, context.Mapper }, Expression.Assign(context.Mapper, Expression.Constant(_mapper)), Expression.Assign(membermappingcontext.SourceMember, sourceValueExp), memberAssignment, //Expression.Invoke(mapping2.MappingExpression, context.ReferenceTracker, // Expression.Convert(subParam,guessedSourceType),targetProperty) //slower but more reliable resolving abstract types/interfaces etc.. Expression.Call(context.Mapper, mapMethod, subParam, targetProperty, context.ReferenceTracker, Expression.Constant(mapping2, typeof(IMapping))) )); } ////better integrated with ultramapper: //var main2 = Expression.Block //( // new[] { context.Mapper }, // Expression.Assign( context.Mapper, Expression.Constant( _mapper ) ), // base.GetComplexMemberExpression( membermapping ) // .ReplaceParameter( context.SourceInstance, "instance" ) // .ReplaceParameter( context.ReferenceTracker, "referenceTracker" ) // .ReplaceParameter( context.Mapper, "mapper" ) // .ReplaceParameter( context.TargetInstance, "instance" ) // .ReplaceParameter( sourceToReplace, "sourceValue" )//!!!!! il problema è la fonte da cui leggere il parametro //); //return main2; } }
private Expression GetMemberAssignment(ReferenceMapperContext context, ParameterExpression subParam, MemberInfo memberInfo, Configuration MapperConfiguration) { if (memberInfo is PropertyInfo propertyInfo) { if (propertyInfo.PropertyType.IsBuiltIn(true)) { var conversion = MapperConfiguration[typeof(SimpleParam), propertyInfo.PropertyType].MappingExpression; //var exceptionParam = Expression.Parameter( typeof( Exception ), "exception" ); //var ctor = typeof( ArgumentException ) // .GetConstructor( new Type[] { typeof( string ), typeof( Exception ) } ); //string error = $"Value not assignable to param '{memberInfo.Name.ToLower()}'";// in command '{paramDef.Name}'"; //var standardBuiltInTypeExp = Expression.TryCatch //( // Expression.Invoke( setter, context.TargetInstance, // Expression.Invoke( conversion, Expression.Convert( subParam, typeof( SimpleParam ) ) ) ), // Expression.Catch( exceptionParam, Expression.Throw // ( // Expression.New( ctor, Expression.Constant( error ), exceptionParam ), // typeof( void ) // ) ) //); //return Expression.Invoke( setter, context.TargetInstance, // Expression.Invoke( conversion, Expression.Convert( subParam, typeof( SimpleParam ) ) ) ); var setter = memberInfo.GetSetterExp(); return(base.GetSimpleMemberExpressionInternal(conversion, context.TargetInstance, Expression.Convert(subParam, typeof(SimpleParam)), setter)); } else { Expression sourceToReplace = subParam; Expression sourcemappingtype = null; if (context.SourceInstance.Type == typeof(ParsedCommand)) { sourcemappingtype = (Expression <Func <ParsedCommand, IParsedParam> >)(( ParsedCommand p ) => p.Param); } else { sourcemappingtype = (Expression <Func <ComplexParam, IParsedParam[]> >)(( ComplexParam p ) => p.SubParams); } if (propertyInfo.PropertyType.IsArray) { sourcemappingtype = (Expression <Func <ArrayParam, IReadOnlyList <IParsedParam> > >)(( ArrayParam p ) => p.Items); var itemsProperty = Expression.Property(Expression.Convert(subParam, typeof(ArrayParam)), nameof(ArrayParam.Items)); sourceToReplace = itemsProperty; } var targetsetprop = context.TargetInstance.Type.GetProperty(memberInfo.Name); var mappingSource = new MappingSource(sourcemappingtype); var mappingTarget = new MappingTarget(targetsetprop); var typeMapping = new TypeMapping(MapperConfiguration, propertyInfo.PropertyType, targetsetprop.PropertyType); var membermapping = new MemberMapping(typeMapping, mappingSource, mappingTarget); var membermappingcontext = new MemberMappingContext(membermapping); var targetProperty = Expression.Property(context.TargetInstance, memberInfo.Name); var targetType = targetProperty.Type; if (targetProperty.Type.IsInterface || targetProperty.Type.IsAbstract) { targetType = typeof(List <>).MakeGenericType(targetType.GetGenericArguments()); } var mapping = MapperConfiguration[targetType, targetsetprop.PropertyType]; var memberAssignment = ((ReferenceMapper)mapping.Mapper).GetMemberAssignment(membermappingcontext) .ReplaceParameter(sourceToReplace, "sourceValue") .ReplaceParameter(targetProperty, "targetValue") .ReplaceParameter(context.TargetInstance, "instance"); if (MapperConfiguration.IsReferenceTrackingEnabled) { var mainExp = ReferenceTrackingExpression.GetMappingExpression( context.ReferenceTracker, subParam, targetProperty, memberAssignment, context.Mapper, _mapper, Expression.Constant(null, typeof(IMapping))); return(mainExp); } else { var mapping2 = MapperConfiguration[subParam.Type, targetProperty.Type]; var mapMethod = ReferenceMapperContext.RecursiveMapMethodInfo .MakeGenericMethod(subParam.Type, targetProperty.Type); return(Expression.Block ( new[] { context.Mapper }, Expression.Assign(context.Mapper, Expression.Constant(_mapper)), memberAssignment, Expression.Call(context.Mapper, mapMethod, subParam, targetProperty, context.ReferenceTracker, Expression.Constant(mapping2, typeof(IMapping))) )); } } } else if (memberInfo is MethodInfo methodInfo) { var parametersExps = new List <Expression>(); var methodParams = methodInfo.GetParameters(); Expression <Func <IParsedParam[], ParameterInfo, object> > selectParamExp = (parsedparams, methodparam) => SelectParam(parsedparams, methodparam); for (int i = 0; i < methodParams.Length; i++) { var param = methodParams[i]; var paramType = param.ParameterType.IsBuiltIn(true) ? typeof(SimpleParam) : typeof(ComplexParam); if (!param.ParameterType.IsBuiltIn(false) && param.ParameterType.IsEnumerable()) { paramType = typeof(ArrayParam); } var itemMapping = MapperConfiguration[paramType, param.ParameterType].MappingExpression; var convertExp = (Expression)Expression.NewArrayInit(typeof(IParsedParam), Expression.Convert( Expression.Property(context.SourceInstance, nameof(ParsedCommand.Param)), paramType)); if (methodParams.Length > 1) { convertExp = Expression.Property ( Expression.Convert ( Expression.Property(context.SourceInstance, nameof(ParsedCommand.Param)), typeof(ComplexParam) ), nameof(ComplexParam.SubParams) ); } if (paramType == typeof(SimpleParam)) { var paramExp = Expression.Invoke ( itemMapping, Expression.Convert ( Expression.Invoke(selectParamExp, convertExp, Expression.Constant(param)), paramType ) ); parametersExps.Add(paramExp); } else { if (param.ParameterType.IsArray) { var tempTarget = Expression.Parameter(param.ParameterType, "temptarget"); var selectedParam = Expression.Parameter(paramType, "selectedParam"); var getCount = typeof(System.Linq.Enumerable).GetMethods( BindingFlags.Static | BindingFlags.Public) .First(m => { if (m.Name != nameof(System.Linq.Enumerable.Count)) { return(false); } var parameters = m.GetParameters(); if (parameters.Length != 1) { return(false); } return(parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable <>)); }) .MakeGenericMethod(typeof(IParsedParam)); Expression GetNewInstanceWithReservedCapacity() { var constructorWithCapacity = param.ParameterType.GetConstructor(new Type[] { typeof(int) }); if (constructorWithCapacity == null) { return(null); } var itemsProperty = Expression.Property(Expression.Convert(selectedParam, typeof(ArrayParam)), nameof(ArrayParam.Items)); var getCountMethod = Expression.Call(null, getCount, itemsProperty); return(Expression.New(constructorWithCapacity, getCountMethod)); } var paramExp = Expression.Block ( new[] { tempTarget, selectedParam }, Expression.Assign(selectedParam, Expression.Convert ( Expression.Invoke(selectParamExp, convertExp, Expression.Constant(param)), paramType )), Expression.Invoke(debugExp, selectedParam), Expression.Assign(tempTarget, GetNewInstanceWithReservedCapacity()), Expression.Invoke ( itemMapping, context.ReferenceTracker, selectedParam, tempTarget ), tempTarget ); parametersExps.Add(paramExp); } else { var targetParamType = param.ParameterType; if (param.ParameterType.IsInterface || param.ParameterType.IsAbstract) { targetParamType = typeof(List <>).MakeGenericType(targetParamType.GetGenericArguments()); } var tempTarget = Expression.Parameter(param.ParameterType, "temptarget"); var paramExp = Expression.Block ( new[] { tempTarget }, Expression.Assign(tempTarget, Expression.New(targetParamType)), Expression.Invoke ( itemMapping, context.ReferenceTracker, Expression.Convert ( Expression.Invoke(selectParamExp, convertExp, Expression.Constant(param)), paramType ), tempTarget ), tempTarget ); parametersExps.Add(paramExp); } } } //optional parameters are mandatory with Expression.Call: pass the default value return(Expression.Block ( Expression.Call(context.TargetInstance, methodInfo, parametersExps.ToArray()) )); } throw new NotSupportedException(); }