private MemberInitExpression GetAnonymousTypeMemberInitExpression(Dictionary <string, Expression> bindingExpressions, Type oldType) { Type newAnonymousType = AnonymousTypeFactory.CreateAnonymousType(bindingExpressions.ToDictionary(a => a.Key, a => a.Value.Type)); TypeMappings.AddTypeMapping(ConfigurationProvider, oldType, newAnonymousType); ConfigureAnonymousTypeMaps(oldType, newAnonymousType); return(Expression.MemberInit ( Expression.New(newAnonymousType), bindingExpressions .ToDictionary(be => be.Key, be => newAnonymousType.GetProperty(be.Key)) .Select(member => Expression.Bind(member.Value, bindingExpressions[member.Key])) )); }
protected override Expression VisitMethodCall(MethodCallExpression node) { var parameterExpression = node.GetParameterExpression(); if (parameterExpression == null) { return(base.VisitMethodCall(node)); } InfoDictionary.Add(parameterExpression, TypeMappings); var listOfArgumentsForNewMethod = node.Arguments.Aggregate(new List <Expression>(), (lst, next) => { var mappedNext = ArgumentMapper.Create(this, next).MappedArgumentExpression; TypeMappings.AddTypeMapping(next.Type, mappedNext.Type); lst.Add(mappedNext); return(lst); });//Arguments could be expressions or other objects. e.g. s => s.UserId or a string "ZZZ". For extention methods node.Arguments[0] is usually the helper object itself //type args are the generic type args e.g. T1 and T2 MethodName<T1, T2>(method arguments); var typeArgsForNewMethod = node.Method.IsGenericMethod ? node.Method.GetGenericArguments().Select(i => TypeMappings.ContainsKey(i) ? TypeMappings[i] : i).ToList()//not converting the type it is not in the typeMappings dictionary : null; MethodCallExpression resultExp; if (!node.Method.IsStatic) { var instance = ArgumentMapper.Create(this, node.Object).MappedArgumentExpression; resultExp = node.Method.IsGenericMethod ? Expression.Call(instance, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray()) : Expression.Call(instance, node.Method, listOfArgumentsForNewMethod.ToArray()); } else { resultExp = node.Method.IsGenericMethod ? Expression.Call(node.Method.DeclaringType, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray()) : Expression.Call(node.Method, listOfArgumentsForNewMethod.ToArray()); } return(resultExp); }
protected override Expression VisitMethodCall(MethodCallExpression node) { var parameterExpression = node.GetParameterExpression(); if (parameterExpression != null) { InfoDictionary.Add(parameterExpression, TypeMappings); } var listOfArgumentsForNewMethod = node.Arguments.Aggregate(new List <Expression>(), (lst, next) => { var mappedNext = this.Visit(next); TypeMappings.AddTypeMapping(ConfigurationProvider, next.Type, mappedNext.Type); lst.Add(mappedNext); return(lst); });//Arguments could be expressions or other objects. e.g. s => s.UserId or a string "ZZZ". For extention methods node.Arguments[0] is usually the helper object itself //type args are the generic type args e.g. T1 and T2 MethodName<T1, T2>(method arguments); var typeArgsForNewMethod = node.Method.IsGenericMethod ? node.Method.GetGenericArguments().Select(type => this.TypeMappings.ReplaceType(type)).ToList()//not converting the type it is not in the typeMappings dictionary : null; ConvertTypesIfNecessary(node.Method.GetParameters(), listOfArgumentsForNewMethod, node.Method); return(node.Method.IsStatic ? GetStaticExpression() : GetInstanceExpression(this.Visit(node.Object))); MethodCallExpression GetInstanceExpression(Expression instance) => node.Method.IsGenericMethod ? Expression.Call(instance, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray()) : Expression.Call(instance, node.Method, listOfArgumentsForNewMethod.ToArray()); MethodCallExpression GetStaticExpression() => node.Method.IsGenericMethod ? Expression.Call(node.Method.DeclaringType, node.Method.Name, typeArgsForNewMethod.ToArray(), listOfArgumentsForNewMethod.ToArray()) : Expression.Call(node.Method, listOfArgumentsForNewMethod.ToArray()); }
protected void FindDestinationFullName(Type typeSource, Type typeDestination, string sourceFullName, List <PropertyMapInfo> propertyMapInfoList) { const string period = "."; bool BothTypesAreAnonymous() => IsAnonymousType(typeSource) && IsAnonymousType(typeDestination); TypeMap GetTypeMap() => BothTypesAreAnonymous() ? anonymousTypesConfigurationProvider.CheckIfTypeMapExists(sourceType: typeDestination, destinationType: typeSource) : ConfigurationProvider.CheckIfTypeMapExists(sourceType: typeDestination, destinationType: typeSource); //The destination becomes the source because to map a source expression to a destination expression, //we need the expressions used to create the source from the destination if (typeSource == typeDestination) { var sourceFullNameArray = sourceFullName.Split(new[] { period[0] }, StringSplitOptions.RemoveEmptyEntries); sourceFullNameArray.Aggregate(propertyMapInfoList, (list, next) => { if (list.Count == 0) { AddPropertyMapInfo(typeSource, next, list); } else { var last = list[list.Count - 1]; AddPropertyMapInfo(last.CustomExpression == null ? last.DestinationPropertyInfos[last.DestinationPropertyInfos.Count - 1].GetMemberType() : last.CustomExpression.ReturnType, next, list); } return(list); }); return; } if (GenericTypeDefinitionsAreEquivalent(typeSource, typeDestination)) { if (sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) < 0) { //sourceFullName is a member of the generic type definition so just add the members PropertyMapInfo AddPropertyMapInfo(typeDestination, sourceFullName, propertyMapInfoList); var sourceType = typeSource.GetFieldOrProperty(sourceFullName).GetMemberType(); var destType = typeDestination.GetFieldOrProperty(sourceFullName).GetMemberType(); TypeMappings.AddTypeMapping(ConfigurationProvider, sourceType, destType); return; } else { //propertyName is a member of the generic type definition so just add the members PropertyMapInfo var propertyName = sourceFullName.Substring(0, sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase)); AddPropertyMapInfo(typeDestination, propertyName, propertyMapInfoList); var sourceType = typeSource.GetFieldOrProperty(propertyName).GetMemberType(); var destType = typeDestination.GetFieldOrProperty(propertyName).GetMemberType(); TypeMappings.AddTypeMapping(ConfigurationProvider, sourceType, destType); var childFullName = sourceFullName.Substring(sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) + 1); FindDestinationFullName(sourceType, destType, childFullName, propertyMapInfoList); return; } } var typeMap = GetTypeMap(); PathMap pathMap = typeMap.FindPathMapByDestinationFullPath(destinationFullPath: sourceFullName); if (pathMap != null) { propertyMapInfoList.Add(new PropertyMapInfo(pathMap.CustomMapExpression, new List <MemberInfo>())); return; } if (sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) < 0) { var propertyMap = typeMap.GetMemberMapByDestinationProperty(sourceFullName); var sourceMemberInfo = typeSource.GetFieldOrProperty(propertyMap.GetDestinationName()); if (propertyMap.ValueResolverConfig != null) { throw new InvalidOperationException(Resource.customResolversNotSupported); } if (propertyMap.CustomMapExpression == null && !propertyMap.SourceMembers.Any()) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.srcMemberCannotBeNullFormat, typeSource.Name, typeDestination.Name, sourceFullName)); } // CompareSourceAndDestLiterals // ( // propertyMap.CustomMapExpression != null ? propertyMap.CustomMapExpression.ReturnType : propertyMap.SourceMember.GetMemberType(), // propertyMap.CustomMapExpression != null ? propertyMap.CustomMapExpression.ToString() : propertyMap.SourceMember.Name, // sourceMemberInfo.GetMemberType() // ); // void CompareSourceAndDestLiterals(Type mappedPropertyType, string mappedPropertyDescription, Type sourceMemberType) // { // //switch from IsValueType to IsLiteralType because we do not want to throw an exception for all structs // if ((mappedPropertyType.IsLiteralType() || sourceMemberType.IsLiteralType()) && sourceMemberType != mappedPropertyType) // throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.expressionMapValueTypeMustMatchFormat, mappedPropertyType.Name, mappedPropertyDescription, sourceMemberType.Name, propertyMap.GetDestinationName())); // } if (propertyMap.IncludedMember?.ProjectToCustomSource != null) { propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.IncludedMember.ProjectToCustomSource, new List <MemberInfo>())); } propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.CustomMapExpression, propertyMap.SourceMembers.ToList())); } else { var propertyName = sourceFullName.Substring(0, sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase)); var propertyMap = typeMap.GetMemberMapByDestinationProperty(propertyName); var sourceMemberInfo = typeSource.GetFieldOrProperty(propertyMap.GetDestinationName()); if (propertyMap.CustomMapExpression == null && !propertyMap.SourceMembers.Any())//If sourceFullName has a period then the SourceMember cannot be null. The SourceMember is required to find the ProertyMap of its child object. { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.srcMemberCannotBeNullFormat, typeSource.Name, typeDestination.Name, propertyName)); } if (propertyMap.IncludedMember?.ProjectToCustomSource != null) { propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.IncludedMember.ProjectToCustomSource, new List <MemberInfo>())); } propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.CustomMapExpression, propertyMap.SourceMembers.ToList())); var childFullName = sourceFullName.Substring(sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) + 1); FindDestinationFullName(sourceMemberInfo.GetMemberType(), propertyMap.CustomMapExpression == null ? propertyMap.SourceMember.GetMemberType() : propertyMap.CustomMapExpression.ReturnType, childFullName, propertyMapInfoList); } }