예제 #1
0
        public Transformer(Func <Type, MemberInfo, int> membersOrder1 = null, Func <Type, MemberInfo, int> membersOrder2 = null)
        {
            if (!TransformerHelper.CheckCompatible(typeof(T1), typeof(T2), new HashSet <Type>(), membersOrder1, membersOrder2))
            {
                throw new ArgumentException(String.Format("{0} not compatible with {1}", typeof(T1).ToString(), typeof(T2).ToString()));
            }

            Type1         = typeof(T1);
            Type2         = typeof(T2);
            MembersOrder1 = membersOrder1;
            MembersOrder2 = membersOrder2;

            to   = CreateToMethod().Compile();
            from = CreateFromMethod().Compile();
        }
예제 #2
0
        public Expression <Func <T2, T1> > CreateFromMethod()
        {
            var value2 = Expression.Parameter(Type2);
            var value1 = Expression.Variable(Type1);

            List <Expression> list = new List <Expression>();

            if (TransformerHelper.IsEqualsTypes(Type1, Type2))
            {
                list.Add(Expression.Label(Expression.Label(Type2), value2));
            }
            else
            {
                list.Add(TransformerHelper.BuildBody(value1, value2, MembersOrder1, MembersOrder2));
                list.Add(Expression.Label(Expression.Label(Type1), value1));
            }

            return(Expression.Lambda <Func <T2, T1> >(TransformerHelper.IsEqualsTypes(Type1, Type2) ? list[0] : Expression.Block(typeof(T1), new ParameterExpression[] { value1 }, list), value2));
        }
예제 #3
0
        public DataTransformer(Type type2, Func <Type, MemberInfo, int> membersOrder1 = null, Func <Type, MemberInfo, int> membersOrder2 = null)
        {
            if (!TransformerHelper.CheckCompatible(typeof(T), type2, new HashSet <Type>(), membersOrder1, membersOrder2))
            {
                throw new ArgumentException(String.Format("Type {0} is not compatible with {1}", typeof(T), type2));
            }

            Type1 = typeof(T);
            Type2 = type2;

            MembersOrder1 = membersOrder1;
            MembersOrder2 = membersOrder2;

            LambdaTo = CreateToMethod();
            to       = LambdaTo.Compile();

            LambdaFrom = CreateFromMethod();
            from       = LambdaFrom.Compile();
        }
예제 #4
0
        public Expression <Func <T, IData> > CreateToMethod()
        {
            var value = Expression.Parameter(Type1);
            var data  = Expression.Variable(typeof(Data <>).MakeGenericType(Type2));

            List <Expression> list = new List <Expression>();

            if (TransformerHelper.IsEqualsTypes(Type1, Type2))
            {
                list.Add(Expression.Label(Expression.Label(typeof(IData)), Expression.New(data.Type.GetConstructor(new Type[] { Type1 }), value)));
            }
            else
            {
                list.Add(Expression.Assign(data, Expression.New(data.Type.GetConstructor(new Type[] { }))));
                list.Add(TransformerHelper.BuildBody(data.Value(), value, MembersOrder1, MembersOrder2));
                list.Add(Expression.Label(Expression.Label(data.Type), data));
            }

            return(Expression.Lambda <Func <T, IData> >(TransformerHelper.IsEqualsTypes(Type1, Type2) ? list[0] : Expression.Block(typeof(IData), new ParameterExpression[] { data }, list), value));
        }
예제 #5
0
        public Expression <Func <IData, T> > CreateFromMethod()
        {
            var idata = Expression.Parameter(typeof(IData));
            var data  = Expression.Variable(typeof(Data <>).MakeGenericType(Type2));
            var value = Expression.Variable(typeof(T));

            List <Expression> list = new List <Expression>();

            if (TransformerHelper.IsEqualsTypes(Type1, Type2))
            {
                list.Add(Expression.Label(Expression.Label(Type1), Expression.Convert(idata, data.Type).Value()));
            }
            else
            {
                list.Add(Expression.Assign(data, Expression.Convert(idata, data.Type)));
                list.Add(TransformerHelper.BuildBody(value, data.Value(), MembersOrder1, MembersOrder2));
                list.Add(Expression.Label(Expression.Label(Type1), value));
            }

            return(Expression.Lambda <Func <IData, T> >(TransformerHelper.IsEqualsTypes(Type1, Type2) ? list[0] : Expression.Block(Type1, new ParameterExpression[] { data, value }, list), idata));
        }
예제 #6
0
        public static Expression BuildBody(Expression Value1, Expression Value2, Func <Type, MemberInfo, int> membersOrder1, Func <Type, MemberInfo, int> membersOrder2)
        {
            var type1 = Value1.Type;
            var type2 = Value2.Type;

            if (type1 == typeof(Guid) || type2 == typeof(Guid))
            {
                return(Expression.Assign(Value1,
                                         type1 == typeof(Guid) ?
                                         Value2.Type == typeof(Guid) ? Value2 : Expression.New(type1.GetConstructor(new Type[] { typeof(byte[]) }), Value2) :
                                         Expression.Call(Value2, type2.GetMethod("ToByteArray"))
                                         ));
            }

            if (type1.IsEnum || type2.IsEnum)
            {
                return(Expression.Assign(Value1, Expression.Convert(Value2, type1)));
            }

            if (IsEqualsTypes(type1, type2))
            {
                return(Expression.Assign(Value1, Value2));
            }

            if (IsNumberType(type1) && TransformerHelper.IsNumberType(type2))
            {
                return(Expression.Assign(Value1, Expression.Convert(Value2, type1)));
            }

            if (type1.IsKeyValuePair())
            {
                var key   = Expression.Variable(type1.GetGenericArguments()[0]);
                var value = Expression.Variable(type1.GetGenericArguments()[1]);

                return(Expression.Assign(Value1,
                                         Expression.New((typeof(KeyValuePair <,>).MakeGenericType(key.Type, value.Type)).GetConstructor(new Type[] { key.Type, value.Type }),
                                                        Expression.Block(key.Type,
                                                                         new ParameterExpression[] { key },
                                                                         BuildBody(key, Expression.PropertyOrField(Value2, type2.IsKeyValuePair() ? "Key" : DataTypeUtils.GetPublicMembers(Value2.Type, membersOrder2).First().Name), membersOrder1, membersOrder2),
                                                                         Expression.Label(Expression.Label(key.Type), key)),
                                                        Expression.Block(value.Type,
                                                                         new ParameterExpression[] { value },
                                                                         BuildBody(value, Expression.PropertyOrField(Value2, type2.IsKeyValuePair() ? "Value" : DataTypeUtils.GetPublicMembers(Value2.Type, membersOrder2).Last().Name), membersOrder1, membersOrder2),
                                                                         Expression.Label(Expression.Label(value.Type), value))
                                                        )));
            }

            if (type1.IsList() || type1.IsArray)
            {
                var element = Expression.Variable(type1.IsArray ? type1.GetElementType() : type1.GetGenericArguments()[0]);

                var block = Expression.Block(new ParameterExpression[] { element },
                                             Expression.Assign(Value1, Expression.New(Value1.Type.GetConstructor(new Type[] { typeof(int) }), Expression.PropertyOrField(Value2, type2.IsList() ? "Count" : "Length"))),
                                             Value2.For(i =>
                {
                    return(type2.IsList() ?
                           (Expression)Expression.Call(Value1, type1.GetMethod("Add"), BuildBody(element, Value2.This(i), membersOrder1, membersOrder2)) :
                           Expression.Assign(Expression.ArrayAccess(Value1, i), BuildBody(element, Expression.ArrayAccess(Value2, i), membersOrder1, membersOrder2)));
                },
                                                        Expression.Label())
                                             );

                return(Expression.IfThenElse(Expression.NotEqual(Value2, Expression.Constant(null)),
                                             block,
                                             Expression.Assign(Value1, Expression.Constant(null, Value1.Type))));
            }

            if (type1.IsDictionary())
            {
                if (!DataType.IsPrimitiveType(type1.GetGenericArguments()[0]) && type1.GetGenericArguments()[0] == typeof(Guid))
                {
                    throw new NotSupportedException(String.Format("Dictionary<{0}, TValue>", type1.GetGenericArguments()[0]));
                }

                var key   = Expression.Variable(type1.GetGenericArguments()[0]);
                var value = Expression.Variable(type1.GetGenericArguments()[1]);

                var block = Expression.Block(new ParameterExpression[] { key, value },
                                             Expression.Assign(Value1, type2.GetGenericArguments()[0] == typeof(byte[]) ?
                                                               Expression.New(type1.GetConstructor(new Type[] { typeof(int), typeof(IEqualityComparer <byte[]>) }), Expression.PropertyOrField(Value2, "Count"), Expression.Field(null, typeof(BigEndianByteArrayEqualityComparer), "Instance")) :
                                                               Expression.New(type1.GetConstructor(new Type[] { typeof(int) }), Expression.PropertyOrField(Value2, "Count"))),
                                             Value2.ForEach(current =>
                                                            Expression.Call(Value1, type1.GetMethod("Add"),
                                                                            BuildBody(key, Expression.Property(current, "Key"), membersOrder1, membersOrder2),
                                                                            BuildBody(value, Expression.Property(current, "Value"), membersOrder1, membersOrder2)),
                                                            Expression.Label()
                                                            ));

                return(Expression.IfThenElse(Expression.NotEqual(Value2, Expression.Constant(null)),
                                             block,
                                             Expression.Assign(Value1, Expression.Constant(null, Value1.Type))));
            }

            if (type1.IsNullable())
            {
                var data1Var = Expression.Variable(Value1.Type);
                var data2Var = Expression.Variable(Value2.Type);

                List <Expression> list = new List <Expression>();

                var block = Expression.Block(new ParameterExpression[] { data1Var, data2Var },
                                             Expression.Assign(data2Var, Value2),
                                             Expression.Assign(data1Var, Expression.New(
                                                                   type1.GetConstructor(new Type[] { type1.GetGenericArguments()[0] }),
                                                                   Expression.PropertyOrField(data2Var, type2.IsNullable() ? "Value" :
                                                                                              DataTypeUtils.GetPublicMembers(type2, membersOrder2).First().Name))),
                                             Expression.Assign(Value1, data1Var)
                                             );

                return(Expression.IfThenElse(Expression.NotEqual(Value2, Expression.Constant(null, type2)),
                                             block,
                                             Expression.Assign(Value1, Expression.Constant(null, type1))
                                             ));
            }

            if (type1.IsClass || type1.IsStruct())
            {
                var data1Var = Expression.Variable(Value1.Type);
                var data2Var = Expression.Variable(Value2.Type);

                List <Expression> list = new List <Expression>();
                list.Add(Expression.Assign(data1Var, Expression.New(data1Var.Type)));

                List <MemberInfo> members1 = DataTypeUtils.GetPublicMembers(Value1.Type, membersOrder1).ToList();

                List <MemberInfo> members2 = new List <MemberInfo>();
                if (type2.IsKeyValuePair() || type2.IsNullable())
                {
                    if (type2.IsKeyValuePair())
                    {
                        members2.Add(type2.GetMember("Key")[0]);
                    }

                    members2.Add(type2.GetMember("Value")[0]);
                }
                else
                {
                    members2 = DataTypeUtils.GetPublicMembers(Value2.Type, membersOrder2).ToList();
                }

                for (int i = 0; i < members1.Count; i++)
                {
                    list.Add(BuildBody(Expression.PropertyOrField(data1Var, members1[i].Name), Expression.PropertyOrField(data2Var, members2[i].Name), membersOrder1, membersOrder2));
                }

                list.Add(Expression.Assign(Value1, data1Var));

                if ((type1.IsStruct() || type2.IsStruct()) && !type2.IsNullable())
                {
                    list.Insert(0, Expression.Assign(data2Var, Value2));
                    list.Add(Expression.Label(Expression.Label(Value1.Type), Value1));
                    return(Expression.Block(type1, new ParameterExpression[] { data1Var, data2Var }, list));
                }

                return(Expression.Block(type1, new ParameterExpression[] { data2Var },
                                        Expression.Assign(data2Var, Value2),
                                        Expression.IfThenElse(Expression.NotEqual(data2Var, Expression.Constant(null)),
                                                              Expression.Block(new ParameterExpression[] { data1Var }, list),
                                                              Expression.Assign(Value1, Expression.Constant(null, type1))),
                                        Expression.Label(Expression.Label(type1), Value1)
                                        ));
            }

            throw new NotSupportedException(type1.ToString());
        }