private void CreatBindingFromSimple(ref Tuple<Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget) { // 没有特殊的操作 if (typeSource == typeTarget) { // 创建成员绑定 CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3); } else { // 尝试查找mapper var externalMapper = GetAndCheckMapper(typeSource, typeTarget, configExpression.Item4); // 如果此时未初始化映射器 externalMapper.CreateMappingExpression(_constructorFunc); // 默认情况下,检查对象的null Expression mapExpression = externalMapper.GetMemberInitExpression(); Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(configExpression.Item1.Type), configExpression.Item1.Type); // 修改成员 var expSource = visitorMapper.Visit(configExpression.Item1); var changeParamaterVisitor = new ChangParameterExpressionVisitor(expSource); mapExpression = changeParamaterVisitor.Visit(mapExpression); // 现在可以创建正确的参数。 Expression checkIfNull = Expression.NotEqual(expSource, defaultExpression); // 创建条件 var checkExpression = Expression.Condition(checkIfNull, mapExpression, Expression.Constant(MapperHelper.GetDefaultValue(mapExpression.Type), mapExpression.Type), mapExpression.Type); var bindExpression = Expression.Bind(propTarget, checkExpression); // 找到了映射器但没有配置 if (string.IsNullOrEmpty(configExpression.Item4)) { configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name); } memberForNew.Add(bindExpression); } }
private void CreatBindingFromSimple(ref Tuple <Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget) { // no specific action. if (typeSource == typeTarget) { // We create the binding. CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3); } else { // Try to find a mapper. MapperConfigurationBase externalMapper = GetAndCheckMapper(typeSource, typeTarget, configExpression.Item4); // If the mapper is not initialized at this moment externalMapper.CreateMappingExpression(constructorFunc); // By default, check the nullity of the object. Expression mapExpression = externalMapper.GetMemberInitExpression(); Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(configExpression.Item1.Type), configExpression.Item1.Type); // To change the parameter. Expression expSource = visitorMapper.Visit(configExpression.Item1, false); ChangParameterExpressionVisitor changeParamaterVisitor = new ChangParameterExpressionVisitor(expSource); mapExpression = changeParamaterVisitor.Visit(mapExpression); // Now we can create with the good parameters. Expression checkIfNull = Expression.NotEqual(expSource, defaultExpression); // Create condition. var checkExpression = Expression.Condition(checkIfNull, mapExpression, Expression.Constant(MapperHelper.GetDefaultValue(mapExpression.Type), mapExpression.Type), mapExpression.Type); MemberAssignment bindExpression = Expression.Bind(propTarget, checkExpression); // We find the mapper and not configured. if (string.IsNullOrEmpty(configExpression.Item4)) { configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name); } memberForNew.Add(bindExpression); } }
private void CreateBindingFromList(ref Tuple<Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget) { var sourceTypeList = TypeSystem.GetElementType(typeSource); var destTypeList = TypeSystem.GetElementType(typeTarget); if (sourceTypeList == destTypeList) { if (configExpression.Item2.NodeType == ExpressionType.MemberAccess) { CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3); } } // 使用Enumerable类的select方法来更改类型 else { var externalMapper = GetAndCheckMapper(sourceTypeList, destTypeList, configExpression.Item4); externalMapper.CreateMappingExpression(_constructorFunc); MemberAssignment expBind; var expSource = configExpression.Item1; var visitor = new ChangParameterExpressionVisitor(paramClassSource); expSource = visitor.Visit(expSource); // 为了与EF / LINQ2SQL兼容。 var expMappeur = externalMapper.GetGenericLambdaExpression(); // 创建对Select方法的调用,在Enumerable的Select中插入一个lambda表达式(参数是一个委托),通常情况下,这是不可能的,但(个人认为)编译器就像这样创建并且LINQ2SQL / EF是可以进行sql查询的 Expression select = Expression.Call(_selectMethod.MakeGenericMethod(sourceTypeList, destTypeList), new[] { expSource, expMappeur }); // 创建对ToList方法的调用 Expression toList = Expression.Call(_toListMethod.MakeGenericMethod(destTypeList), select); if (configExpression.Item3) // 如果要检查无效(使用EF / LinqTosql,则不需要)。 { // 测试source的属性是否为null。 Expression checkIfNull = Expression.NotEqual(expSource, Expression.Constant(MapperHelper.GetDefaultValue(expSource.Type), expSource.Type)); // 有时候ToList方法不起作用,则使用实现ToList不起作用的类 Expression asExp = Expression.TypeAs(toList, propTarget.PropertyType); // 创建条件表达式 Expression expCondition = Expression.Condition(checkIfNull, asExp, Expression.Constant(MapperHelper.GetDefaultValue(typeTarget), typeTarget)); // 分配给目标属性。 expBind = Expression.Bind(propTarget, expCondition); } else { // 分配给目标属性。 expBind = Expression.Bind(propTarget, toList); } // 查找mapper if (string.IsNullOrEmpty(configExpression.Item4)) { configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name); } memberForNew.Add(expBind); } }
/// <summary> /// 为现有目标对象创建成员 /// </summary> public virtual void CreateMemberAssignementForExistingTarget() { if (PropertiesMapping.Count <= 0) { return; } // 用于更改原始表达式的参数。 var paramTarget = Expression.Parameter(TargetType, paramClassSource.Name.Replace("s", "t")); var finalAssign = new List<Expression>(); foreach (var item in PropertiesMapping) { var propToAssign = new ChangParameterExpressionVisitor(paramTarget).Visit(item.Item2); var assignExpression = new ChangParameterExpressionVisitor(paramClassSource).Visit(item.Item1); var sourceType = TypeSystem.GetElementType(item.Item2.Type); var targetType = TypeSystem.GetElementType(item.Item1.Type); if (string.IsNullOrEmpty(item.Item4)) { object defaultValue = MapperHelper.GetDefaultValue(item.Item2.Type); Expression defaultExpression = Expression.Constant(defaultValue, item.Item2.Type); Expression checkIfNull = Expression.NotEqual(assignExpression, defaultExpression); if (item.Item3) { Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression)); finalAssign.Add(setIf); } else { if (!IsListOf(propToAssign.Type)) { finalAssign.Add(Expression.Assign(propToAssign, assignExpression)); } else { if (sourceType == targetType) { Expression toListExp = Expression.Call(_toListMethod.MakeGenericMethod(sourceType), assignExpression); Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression)); finalAssign.Add(setIf); finalAssign.Add(toListExp); } } } } else // 来自其他映射器。 { var mapper = GetMapper(sourceType, targetType, false, item.Item4); if (mapper == null) { continue; } mapper.Initialize(_constructorFunc); Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(item.Item2.Type), item.Item2.Type); if (!IsListOf(propToAssign.Type)) { ChangParameterExpressionVisitor changeVisitor = new ChangParameterExpressionVisitor(propToAssign, assignExpression); Expression modifiedExpression = changeVisitor.Visit(mapper.expressionForExisting.Body); Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression); Expression setIf = Expression.IfThen(checkIfNull, modifiedExpression); assignExpression = setIf; } else { Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression); Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression)); assignExpression = setIf; } finalAssign.Add(assignExpression); } } if (finalAssign.Count > 0 && _delegateCallForExisting == null) { expressionForExisting = Expression.Lambda(Expression.Block(typeof(void), finalAssign), paramClassSource, paramTarget); // 编译 _delegateCallForExisting = expressionForExisting.Compile(); } }
/// <summary> /// 将表达式分布在此类中更专一的访问方法之一。 /// </summary> /// <param name="node">访问表达式树</param> /// <param name="checkIfNullity">检查null值</param> /// <returns> /// 改变表达式,如果它或它的任何子表达式被修改; 否则,返回原始表达式。 /// </returns> public Expression Visit(Expression node, bool checkIfNullity = false) { _checkNull = checkIfNullity; if (node == null) { return(node); } if (_checkNull) { Expression result; switch (node.NodeType) { case ExpressionType.MemberAccess: result = VisitMember(node as MemberExpression); break; case ExpressionType.Parameter: result = VisitParameter(node as ParameterExpression); break; case ExpressionType.Convert: result = VisitMember((node as UnaryExpression).Operand as MemberExpression); break; case ExpressionType.Lambda: LambdaExpression lambda = ((LambdaExpression)node); // 子表达式树 if (lambda.Body.NodeType != ExpressionType.Lambda) { result = Visit(lambda.Body); } else { return(lambda); } break; default: result = base.Visit(node); break; } bool isFirst = true; Expression previousExpression = null; if (_membersToCheck.Count > 1) { // 在分配值之前测试所有子对象。例如:source.SubClass.SubClass2.MyProperty。 foreach (MemberExpression item in _membersToCheck) { if (!isFirst) // 不要测试该属性的值。 { object defaultValue = MapperHelper.GetDefaultValue(item.Type); // 创建默认值的验证。 Expression notDefaultValue = Expression.NotEqual(item, Expression.Constant(defaultValue, item.Type)); Expression conditional = null; // 它创建了包含上述条件的条件。 if (previousExpression != null) { object defaultPreviousValue = MapperHelper.GetDefaultValue(previousExpression.Type); conditional = Expression.Condition(notDefaultValue, previousExpression, Expression.Constant(defaultPreviousValue, previousExpression.Type)); } // 它会影响新创建的条件,这些条件将成为之前的条件。 previousExpression = conditional; } else // 属性 { previousExpression = item; isFirst = false; } } return(previousExpression); } // 不需要递归的元素。 if (_membersToCheck.Count == 1) { var item = _membersToCheck.Peek(); object defaultValue = MapperHelper.GetDefaultValue(item.Type); // 创建默认值的验证。 Expression notDefaultValue = Expression.NotEqual(item, Expression.Constant(defaultValue, item.Type)); Expression conditional = Expression.Condition(notDefaultValue, item, Expression.Constant(defaultValue, item.Type)); return(conditional); } return(result); } // 默认返回(更改参数),删除lambda表达式的验证。 if (node.NodeType == ExpressionType.Lambda) { LambdaExpression lambda = (LambdaExpression)node; // 子表达式树 if (lambda.Body.NodeType != ExpressionType.Call) { return(base.Visit(lambda.Body)); } return(lambda); } return(base.Visit(node)); }
private void CreateBindingFromList(ref Tuple <Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget) { Type sourceTypeList = TypeSystem.GetElementType(typeSource); Type destTypeList = TypeSystem.GetElementType(typeTarget); //No change it's easy if (sourceTypeList == destTypeList) { if (configExpression.Item2.NodeType == ExpressionType.MemberAccess) { CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3); } } // Using "Select" of Enumerable class to change type. else { var externalMapper = GetAndCheckMapper(sourceTypeList, destTypeList, configExpression.Item4); externalMapper.CreateMappingExpression(constructorFunc); MemberAssignment expBind = null; Expression expSource = configExpression.Item1; ChangParameterExpressionVisitor visitor = new ChangParameterExpressionVisitor(paramClassSource); expSource = visitor.Visit(expSource); //For compatibility with EF/LINQ2SQL. LambdaExpression expMappeur = externalMapper.GetGenericLambdaExpression(); // We create the call to the Select method. // We insert a lambda expression in select of Enumerable(the parameter is a delegate), // normally, that's impossible but (we think) that the compiler creating like this and that LINQ2SQL/EF can make the sql query. Expression select = Expression.Call(selectMethod.MakeGenericMethod(sourceTypeList, destTypeList), new Expression[] { expSource, expMappeur }); // We create the call to ToList method Expression toList = Expression.Call(toListMethod.MakeGenericMethod(destTypeList), select); if (configExpression.Item3) // If you want check the nullity(with EF/LinqTosql, you don't need). { // Test if the source property is null. Expression checkIfNull = Expression.NotEqual(expSource, Expression.Constant(MapperHelper.GetDefaultValue(expSource.Type), expSource.Type)); Expression expCondition = null; // For boxing some time the ToList method not working. // With a class that implement a list that does not work. Expression asExp = Expression.TypeAs(toList, propTarget.PropertyType); // Create condition expCondition = Expression.Condition(checkIfNull, asExp, Expression.Constant(MapperHelper.GetDefaultValue(typeTarget), typeTarget)); // Assigning to the destination propery. expBind = Expression.Bind(propTarget, expCondition); } else { // Assigning to the destination propery. expBind = Expression.Bind(propTarget, toList); } //We find the mapper if (string.IsNullOrEmpty(configExpression.Item4)) { configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name); } memberForNew.Add(expBind); } }
internal virtual void CreateMemberAssignementForExistingTarget() { if (propertiesMapping.Count > 0) { // For change the parameter of the original expression. var paramTarget = Expression.Parameter(TargetType, paramClassSource.Name.Replace("s", "t")); ChangParameterExpressionVisitor visitSource = new ChangParameterExpressionVisitor(paramClassSource); ChangParameterExpressionVisitor visitTarget = new ChangParameterExpressionVisitor(paramTarget); List <Expression> finalAssign = new List <Expression>(); for (int i = 0; i < propertiesMapping.Count; i++) { var item = propertiesMapping[i]; var propToAssign = visitTarget.Visit(item.Item2); Expression assignExpression = null; assignExpression = visitSource.Visit(item.Item1); Type sourceType = TypeSystem.GetElementType(item.Item2.Type); Type targetType = TypeSystem.GetElementType(item.Item1.Type); if (string.IsNullOrEmpty(item.Item4)) { object defaultValue = MapperHelper.GetDefaultValue(item.Item2.Type); Expression defaultExpression = Expression.Constant(defaultValue, item.Item2.Type); Expression checkIfNull = Expression.NotEqual(assignExpression, defaultExpression); if (item.Item3) { //Create check if null Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression)); finalAssign.Add(setIf); } else { if (!IsListOf(propToAssign.Type)) { finalAssign.Add(Expression.Assign(propToAssign, assignExpression)); } else { //NOT TESTED !!!!! if (sourceType == targetType) { Expression toListExp = Expression.Call(toListMethod.MakeGenericMethod(sourceType), assignExpression); Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression)); finalAssign.Add(setIf); } } } } else // Come from a other mapper. { var mapper = GetMapper(sourceType, targetType, false, item.Item4); if (mapper != null) { mapper.Initialize(constructorFunc); Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(item.Item2.Type), item.Item2.Type); if (!IsListOf(propToAssign.Type)) { ChangParameterExpressionVisitor changeVisitor = new ChangParameterExpressionVisitor(propToAssign, assignExpression); Expression modifiedExpression = changeVisitor.Visit(mapper.expressionForExisting.Body); Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression); Expression setIf = Expression.IfThen(checkIfNull, modifiedExpression); assignExpression = setIf; } else { // Use Select of Enumerable NOT TESTED !!!!! Expression selectExp = Expression.Call(selectMethod.MakeGenericMethod(sourceType), Expression.Constant(mapper.GetDelegate())); Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression); Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression)); assignExpression = setIf; } finalAssign.Add(assignExpression); } } } if (finalAssign.Count > 0 && delegateCallForExisting == null) { expressionForExisting = Expression.Lambda(Expression.Block(typeof(void), finalAssign), paramClassSource, paramTarget); // Assign the delegate. delegateCallForExisting = expressionForExisting.Compile(); } } }
/// <summary> /// Distributes the expression one of the more specialized visit methods in this class. /// </summary> /// <param name="node">Expression to visit.</param> /// <param name="checkIfNullity">Check</param> /// <returns> /// Altered expression, if it or any subexpression was modified; otherwise, returns the original expression. /// </returns> public Expression Visit(Expression node, bool checkIfNullity = false) { checkNull = checkIfNullity; Expression result; if (node == null) { return(node); } if (checkNull) { // Treated our case switch (node.NodeType) { case ExpressionType.MemberAccess: result = VisitMember(node as MemberExpression); break; case ExpressionType.Parameter: result = VisitParameter(node as ParameterExpression); break; case ExpressionType.Convert: result = VisitMember((node as UnaryExpression).Operand as MemberExpression); break; case ExpressionType.Lambda: LambdaExpression lambda = ((LambdaExpression)node); //Sub expression if (lambda.Body.NodeType != ExpressionType.Lambda) { result = Visit(lambda.Body); } else { return(lambda); } break; default: result = base.Visit(node); break; } bool isFirst = true; Expression previousExpression = null; if (membersToCheck.Count > 1) { // We want to test all the sub objects before assigning the value. // Ex: source.SubClass.SubClass2.MyProperty. // Which will give : // source.SubClass != null ? source.SubClass.SubClass2 != null ? source.SubClass.SubClass2.MyProperty :DefaultValueOfProperty :DefaultValueOfProperty. foreach (MemberExpression item in membersToCheck) { if (!isFirst) // Not to test the value of the property back. { object defaultValue = MapperHelper.GetDefaultValue(item.Type); // Creating verification of default value. Expression notDefaultValue = Expression.NotEqual(item, Expression.Constant(defaultValue, item.Type)); Expression conditional = null; // It creates a condition that includes the above condition. if (previousExpression != null) { object defaultPreviousValue = MapperHelper.GetDefaultValue(previousExpression.Type); conditional = Expression.Condition(notDefaultValue, previousExpression, Expression.Constant(defaultPreviousValue, previousExpression.Type)); } // It affects the newly created conditions that will become the previous. previousExpression = conditional; } else // here the requested property. { previousExpression = item; isFirst = false; } } return(previousExpression); } // For one element don't need recusrive. else if (membersToCheck.Count == 1) { var item = membersToCheck.Peek(); object defaultValue = MapperHelper.GetDefaultValue(item.Type); // Creating verification of default value. Expression notDefaultValue = Expression.NotEqual(item, Expression.Constant(defaultValue, item.Type)); Expression conditional; conditional = Expression.Condition(notDefaultValue, item, Expression.Constant(defaultValue, item.Type)); return(conditional); } return(result); } else { // Return by default (with change of the parameter). // To remove validation of the lambda expression. if ((node.NodeType == ExpressionType.Lambda)) { LambdaExpression lambda = ((LambdaExpression)node); // Sub expression. if (lambda.Body.NodeType != ExpressionType.Call) { return(base.Visit(lambda.Body)); } else { return(lambda); } } else { return(base.Visit(node)); } } }