Beispiel #1
0
        public ValueToString(int stringBuilderCapacity, IFormatProvider[] providers, char[] delimiters, Func <Type, MemberInfo, int> membersOrder = null)
        {
            if (!DataType.IsPrimitiveType(typeof(T)) && !typeof(T).HasDefaultConstructor())
            {
                throw new NotSupportedException("No default constructor.");
            }

            bool isSupported = DataTypeUtils.IsAllPrimitive(typeof(T));

            if (!isSupported)
            {
                throw new NotSupportedException("Not all types are primitive.");
            }

            var countOfType = DataType.IsPrimitiveType(typeof(T)) ? 1 : DataTypeUtils.GetPublicMembers(typeof(T), membersOrder).Count();

            if (providers.Length != countOfType)
            {
                throw new ArgumentException("providers.Length != dataType.Length");
            }

            Type                  = typeof(T);
            MembersOrder          = membersOrder;
            StringBuilderCapacity = stringBuilderCapacity;
            Providers             = providers;
            Delimiters            = delimiters;

            to   = CreateToMethod().Compile();
            from = CreateFromMethod().Compile();
        }
Beispiel #2
0
        public static Expression CreateGetHashCodeBody(Expression obj, Func <Type, MemberInfo, int> membersOrder)
        {
            var type = obj.Type;

            if (DataType.IsPrimitiveType(type) || type == typeof(Guid))
            {
                return(GetHashCodeCommand(obj));
            }
            else
            {
                List <Expression> list = new List <Expression>();

                foreach (var member in DataTypeUtils.GetPublicMembers(type, membersOrder))
                {
                    list.Add(GetHashCodeCommand(Expression.PropertyOrField(obj, member.Name)));
                }

                var xor = list[0];
                for (int i = 1; i < list.Count; i++)
                {
                    xor = Expression.ExclusiveOr(list[i], xor);
                }

                return(Expression.Block(typeof(int), Expression.Label(Expression.Label(typeof(int)), xor)));
            }
        }
Beispiel #3
0
        public static Expression CreateParseBody(Expression item, ParameterExpression stringParam, IFormatProvider[] providers, char[] delimiters, Func <Type, MemberInfo, int> membersOrder)
        {
            var array = Expression.Variable(typeof(string[]), "array");

            if (DataType.IsPrimitiveType(item.Type) || DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Count() == 1)
            {
                var member = DataType.IsPrimitiveType(item.Type) ? item : Expression.PropertyOrField(item, DataTypeUtils.GetPublicMembers(item.Type, membersOrder).First().Name);

                Expression value;

                if (member.Type == typeof(String))
                {
                    value = stringParam;
                }
                else if (member.Type == typeof(byte[]))
                {
                    var hexParse = typeof(StringExtensions).GetMethod("ParseHex", new Type[] { typeof(string) });
                    value = Expression.Call(hexParse, stringParam);
                }
                else if (member.Type == typeof(char))
                {
                    var parseMethod = member.Type.GetMethod("Parse", new Type[] { typeof(string) });
                    value = Expression.Call(parseMethod, stringParam);
                }
                else if (member.Type == typeof(bool))
                {
                    var parseMethod = member.Type.GetMethod("Parse");
                    value = Expression.Call(parseMethod, stringParam);
                }
                else
                {
                    var parseMethod = member.Type.GetMethod("Parse", new Type[] { typeof(string), typeof(IFormatProvider) });
                    value = Expression.Call(parseMethod, stringParam, Expression.Constant(providers[0], typeof(IFormatProvider)));
                }

                return(Expression.Assign(member, value));
            }

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

            list.Add(Expression.Assign(array, Expression.Call(stringParam, typeof(string).GetMethod("Split", new Type[] { typeof(char[]) }), new Expression[] { Expression.Constant(delimiters) })));

            int i = 0;

            foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder))
            {
                list.Add(GetParseCommand(Expression.PropertyOrField(item, member.Name), i, array, providers[i++]));
            }

            return(Expression.Block(new ParameterExpression[] { array }, list));
        }
Beispiel #4
0
        public static Expression CreateComparerBody(List <Expression> expressions, List <ParameterExpression> parameters, Expression x, Expression y, CompareOption[] compareOptions, Func <Type, MemberInfo, int> membersOrder)
        {
            var exitPoint = Expression.Label(typeof(int));
            List <Expression>          list      = new List <Expression>();
            List <ParameterExpression> variables = new List <ParameterExpression>();
            bool haveCmp = false;

            if (expressions != null)
            {
                foreach (var expression in expressions)
                {
                    list.Add(expression);
                }
            }

            if (parameters != null)
            {
                foreach (var parameter in parameters)
                {
                    variables.Add(parameter);
                }
            }

            if (DataType.IsPrimitiveType(x.Type) || x.Type == typeof(Guid))
            {
                foreach (var command in GetCompareCommands(x, y, Expression.Variable(typeof(int)), exitPoint, x.Type, compareOptions[0], true))
                {
                    list.Add(command);
                }
            }
            else
            {
                int i   = 0;
                var cmp = Expression.Variable(typeof(int));
                foreach (var field in DataTypeUtils.GetPublicMembers(x.Type, membersOrder))
                {
                    if (!haveCmp && (field.GetUnderlyingType() == typeof(char) || field.GetUnderlyingType() == typeof(byte[]) || field.GetUnderlyingType() == typeof(Decimal) || field.GetUnderlyingType() == typeof(String)))
                    {
                        haveCmp = true;
                        variables.Add(cmp);
                    }

                    foreach (var command in GetCompareCommands(Expression.PropertyOrField(x, field.Name), Expression.PropertyOrField(y, field.Name), cmp, exitPoint, field.GetUnderlyingType(), compareOptions[i++], i == DataTypeUtils.GetPublicMembers(x.Type, membersOrder).Count()))
                    {
                        list.Add(command);
                    }
                }
            }

            return(Expression.Block(typeof(int), variables, list));
        }
Beispiel #5
0
        public static Expression CreateToStringBody(Expression item, int stringBuilderCapacity, IFormatProvider[] providers, char delimiter, Func <Type, MemberInfo, int> membersOrder)
        {
            var stringBuilder = Expression.Variable(typeof(StringBuilder));

            if (DataType.IsPrimitiveType(item.Type) || DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Count() == 1)
            {
                var member = DataType.IsPrimitiveType(item.Type) ? item : Expression.PropertyOrField(item, DataTypeUtils.GetPublicMembers(item.Type, membersOrder).First().Name);

                MethodCallExpression callToString;

                if (member.Type == typeof(byte[]))
                {
                    var toHexMethod = typeof(ByteArrayExtensions).GetMethod("ToHex", new Type[] { typeof(byte[]) });
                    callToString = Expression.Call(toHexMethod, member);
                }
                else if (member.Type == typeof(TimeSpan))
                {
                    var toStringProvider = member.Type.GetMethod("ToString", new Type[] { typeof(String), typeof(IFormatProvider) });
                    callToString = Expression.Call(member, toStringProvider, Expression.Constant(null, typeof(String)), Expression.Constant(providers[0], typeof(IFormatProvider)));
                }
                else
                {
                    var toStringProvider = member.Type.GetMethod("ToString", new Type[] { typeof(IFormatProvider) });
                    callToString = Expression.Call(member, toStringProvider, Expression.Constant(providers[0], typeof(IFormatProvider)));
                }

                return(Expression.Label(Expression.Label(typeof(string)), member.Type == typeof(string) ? (Expression)member : (Expression)callToString));
            }

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

            list.Add(Expression.Assign(stringBuilder, Expression.New(stringBuilder.Type.GetConstructor(new Type[] { typeof(int) }), Expression.Constant(stringBuilderCapacity))));

            int i = 0;

            foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder))
            {
                list.Add(GetAppendCommand(Expression.PropertyOrField(item, member.Name), stringBuilder, providers[i]));

                if (i < DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Count() - 1)
                {
                    list.Add(Expression.Call(stringBuilder, typeof(StringBuilder).GetMethod("Append", new Type[] { typeof(char) }), Expression.Constant(delimiter)));
                }
                i++;
            }

            list.Add(Expression.Label(Expression.Label(typeof(string)), Expression.Call(stringBuilder, typeof(object).GetMethod("ToString"))));

            return(Expression.Block(new ParameterExpression[] { stringBuilder }, list));
        }
Beispiel #6
0
 public static void CheckCompareOptions(Type type, CompareOption[] compareOptions, Func <Type, MemberInfo, int> memberOrder = null)
 {
     if (type.IsClass() || type.IsStruct())
     {
         int i = 0;
         foreach (var member in DataTypeUtils.GetPublicMembers(type, memberOrder).Select(x => x.GetUnderlyingType()).ToArray())
         {
             CheckCompareOption(member, compareOptions[i++]);
         }
     }
     else
     {
         CheckCompareOption(type, compareOptions[0]);
     }
 }
Beispiel #7
0
        public static IFormatProvider[] GetDefaultProviders(Type type, Func <Type, MemberInfo, int> membersOrder = null)
        {
            if (DataType.IsPrimitiveType(type))
            {
                return new IFormatProvider[] { GetDefaultProvider(type) }
            }
            ;

            List <IFormatProvider> providers = new List <IFormatProvider>();

            foreach (var member in DataTypeUtils.GetPublicMembers(type, membersOrder))
            {
                providers.Add(GetDefaultProvider(member.GetUnderlyingType()));
            }

            return(providers.ToArray());
        }
Beispiel #8
0
        public DataToString(Type type, int stringBuilderCapacity, IFormatProvider[] providers, char[] delimiters, Func <Type, MemberInfo, int> membersOrder = null)
        {
            Type = type;
            StringBuilderCapacity = stringBuilderCapacity;
            var typeCount = DataType.IsPrimitiveType(type) ? 1 : DataTypeUtils.GetPublicMembers(type, membersOrder).Count();

            if (providers.Length != typeCount)
            {
                throw new ArgumentException("providers.Length != dataType.Length");
            }

            Providers    = providers;
            Delimiters   = delimiters;
            MembersOrder = membersOrder;

            to   = CreateToMethod().Compile();
            from = CreateFromMethod().Compile();
        }
Beispiel #9
0
        public static Expression ToObjects(Expression item, Func <Type, MemberInfo, int> membersOrder)
        {
            Type[] types = DataType.IsPrimitiveType(item.Type) ? new Type[] { item.Type } : DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Select(x => x.GetUnderlyingType()).ToArray();

            if (types.Length == 1)
            {
                return(Expression.NewArrayInit(typeof(object), Expression.Convert(item, typeof(object))));
            }

            Expression[] values = new Expression[types.Length];
            int          i      = 0;

            foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder))
            {
                values[i++] = Expression.Convert(Expression.PropertyOrField(item, member.Name), typeof(object));
            }

            return(Expression.NewArrayInit(typeof(object), values));
        }
Beispiel #10
0
        public static Expression FromObjects(Expression item, ParameterExpression objectArray, Func <Type, MemberInfo, int> membersOrder)
        {
            Type[] types = DataType.IsPrimitiveType(item.Type) ? new Type[] { item.Type } : DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Select(x => x.GetUnderlyingType()).ToArray();

            if (types.Length == 1)
            {
                return(Expression.Assign(item, Expression.Convert(Expression.ArrayAccess(objectArray, Expression.Constant(0, typeof(int))), types[0])));
            }

            List <Expression> list = new List <Expression>();
            int i = 0;

            foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder))
            {
                list.Add(Expression.Assign(Expression.PropertyOrField(item, member.Name), Expression.Convert(Expression.ArrayAccess(objectArray, Expression.Constant(i, typeof(int))), types[i++])));
            }

            return(Expression.Block(list));
        }
Beispiel #11
0
        public static CompareOption[] GetDefaultCompareOptions(Type type, Func <Type, MemberInfo, int> memberOrder = null)
        {
            if (DataType.IsPrimitiveType(type))
            {
                return new CompareOption[] { GetDefaultCompareOption(type) }
            }
            ;

            if (type == typeof(Guid))
            {
                return new CompareOption[] { GetDefaultCompareOption(type) }
            }
            ;

            if (type.IsClass() || type.IsStruct())
            {
                return(DataTypeUtils.GetPublicMembers(type, memberOrder).Select(x => GetDefaultCompareOption(x.GetUnderlyingType())).ToArray());
            }

            throw new NotSupportedException(type.ToString());
        }
Beispiel #12
0
        public static Expression CreateEqualsBody(Expression x, Expression y, CompareOption[] compareOptions, Func <Type, MemberInfo, int> membersOrder)
        {
            var type      = x.Type;
            var exitPoint = Expression.Label(typeof(bool));

            if (DataType.IsPrimitiveType(type) || type == typeof(Guid))
            {
                return(EqualityComparerHelper.GetEqualsCommand(x, y, compareOptions[0], exitPoint, true));
            }
            else
            {
                List <Expression> list = new List <Expression>();

                int i     = 0;
                int count = DataTypeUtils.GetPublicMembers(type, membersOrder).Count();

                foreach (var member in DataTypeUtils.GetPublicMembers(type, membersOrder))
                {
                    list.Add(GetEqualsCommand(Expression.PropertyOrField(x, member.Name), Expression.PropertyOrField(y, member.Name), compareOptions[i++], exitPoint, i == count));
                }

                return(Expression.Block(typeof(bool), list));
            }
        }
Beispiel #13
0
        private static Expression BuildGetSize(Expression item, int charSize, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth)
        {
            var  type      = item.Type;
            bool canBeNull = CanBeNull(type, allowNull, depth);

            if (type == typeof(Guid))
            {
                return(GetPrimitiveValueSize(Expression.Call(item, type.GetMethod("ToByteArray")), charSize, false));
            }

            if (type.IsEnum())
            {
                return(GetPrimitiveValueSize(Expression.Convert(item, item.Type.GetEnumBaseType()), charSize, canBeNull));
            }

            if (DataType.IsPrimitiveType(type))
            {
                return(GetPrimitiveValueSize(item, charSize, canBeNull));
            }

            if (type.IsKeyValuePair())
            {
                var key   = BuildGetSize(Expression.PropertyOrField(item, "Key"), charSize, membersOrder, allowNull, depth + 1);
                var value = BuildGetSize(Expression.PropertyOrField(item, "Value"), charSize, membersOrder, allowNull, depth + 1);

                return(Expression.Add(key, value));
            }

            if (type.IsArray || type.IsList())
            {
                var listSum    = Expression.Variable(typeof(int));
                var count      = type.IsArray ? (Expression)Expression.ArrayLength(item) : Expression.Property(item, "Count");
                var writeCount = Expression.Call(typeof(CountCompression).GetMethod("GetSize"), Expression.Convert(count, typeof(ulong)));

                int fixedSize = 0;
                var itemType  = type.IsArray ? type.GetElementType() : type.GetGenericArgument(0);
                if (HasFixedSize(itemType, out fixedSize))
                {
                    if (!canBeNull)
                    {
                        return(Expression.Add(writeCount, Expression.Multiply(count, Expression.Constant(fixedSize))));
                    }

                    return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)),
                                                Expression.Add(
                                                    Expression.Add(Expression.Constant(1), writeCount),
                                                    Expression.Multiply(count, Expression.Constant(fixedSize))),
                                                Expression.Constant(1)
                                                ));
                }

                if (!canBeNull)
                {
                    return(Expression.Block(new ParameterExpression[] { listSum },
                                            Expression.Assign(listSum, writeCount),
                                            item.For(i =>
                                                     Expression.AddAssign(listSum, BuildGetSizeWithAssignedOrCurrentVariable(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), charSize, membersOrder, allowNull, depth + 1)),
                                                     Expression.Label()),

                                            Expression.Label(Expression.Label(typeof(int)), listSum)
                                            ));
                }

                return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)),
                                            Expression.Block(new ParameterExpression[] { listSum },
                                                             Expression.Assign(listSum, Expression.Constant(1)),
                                                             Expression.AddAssign(listSum, writeCount),
                                                             item.For(i =>
                                                                      Expression.AddAssign(listSum, BuildGetSizeWithAssignedOrCurrentVariable(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), charSize, membersOrder, allowNull, depth + 1)),
                                                                      Expression.Label()),

                                                             Expression.Label(Expression.Label(typeof(int)), listSum)
                                                             ),
                                            Expression.Constant(1, typeof(int))
                                            ));
            }

            if (type.IsDictionary())
            {
                var keyType = type.GetGenericArgument(0);

                if (!IsSupportDictionaryKeyType(keyType))
                {
                    throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", keyType.ToString()));
                }

                var  valueType = type.GetGenericArgument(1);
                bool isEnum    = type.GetGenericArgument(0).IsEnum();

                if (!DataType.IsPrimitiveType(keyType) && !isEnum && type != typeof(Guid))
                {
                    throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", type.GetGenericArgument(0).ToString()));
                }

                var dictSum = Expression.Variable(typeof(int));

                var count      = Expression.Property(item, "Count");
                var writeCount = Expression.Call(typeof(CountCompression).GetMethod("GetSize"), Expression.Convert(count, typeof(ulong)));

                int keySize   = 0;
                int valueSize = 0;
                if (HasFixedSize(keyType, out keySize) && HasFixedSize(valueType, out valueSize))
                {
                    if (!canBeNull)
                    {
                        return(Expression.Multiply(writeCount, Expression.Constant(keySize + valueSize)));
                    }

                    return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)),
                                                Expression.Add(
                                                    Expression.Constant(1),
                                                    Expression.Multiply(writeCount, Expression.Constant(keySize + valueSize))
                                                    ),
                                                Expression.Constant(1)
                                                ));
                }

                if (!canBeNull)
                {
                    return(Expression.Block(new ParameterExpression[] { dictSum },
                                            Expression.Assign(dictSum, writeCount),
                                            item.ForEach(current =>
                    {
                        var kv = Expression.Variable(current.Type);

                        return Expression.Block(new ParameterExpression[] { kv },
                                                Expression.Assign(kv, current),

                                                Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Key"), charSize, membersOrder, allowNull, depth + 1)),
                                                Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Value"), charSize, membersOrder, allowNull, depth + 1))
                                                );
                    }, Expression.Label()),

                                            Expression.Label(Expression.Label(typeof(int)), dictSum)
                                            ));
                }

                return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)),
                                            Expression.Block(new ParameterExpression[] { dictSum },
                                                             Expression.Assign(dictSum, Expression.Constant(1)),
                                                             Expression.Assign(dictSum, writeCount),
                                                             item.ForEach(current =>
                {
                    var kv = Expression.Variable(current.Type);

                    return Expression.Block(new ParameterExpression[] { kv },
                                            Expression.Assign(kv, current),

                                            Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Key"), charSize, membersOrder, allowNull, depth + 1)),
                                            Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Value"), charSize, membersOrder, allowNull, depth + 1))
                                            );
                }, Expression.Label()),

                                                             Expression.Label(Expression.Label(typeof(int)), dictSum)
                                                             ),

                                            Expression.Constant(1)
                                            ));
            }

            if (type.IsNullable())
            {
                var getSize = BuildGetSize(Expression.PropertyOrField(item, "Value"), charSize, membersOrder, allowNull, depth + 1);

                if (!canBeNull)
                {
                    return(getSize);
                }

                return(Expression.Condition(Expression.PropertyOrField(item, "HasValue"),
                                            Expression.Add(Expression.Constant(1), getSize),
                                            Expression.Constant(1)
                                            ));
            }

            if (type.IsClass() || type.IsStruct())
            {
                List <ParameterExpression> variables = new List <ParameterExpression>();
                List <Expression>          list      = new List <Expression>();

                var members = DataTypeUtils.GetPublicMembers(type, membersOrder).ToList();

                Expression megaAdd = Expression.Empty();

                for (int i = 0; i < members.Count; i++)
                {
                    var mType = members[i].GetUnderlyingType();

                    int mSize = 0;
                    if (HasFixedSize(mType, out mSize))
                    {
                        var getSize = BuildGetSize(Expression.PropertyOrField(item, members[i].Name), charSize, membersOrder, allowNull, depth + 1);
                        megaAdd = (i == 0) ? getSize : Expression.Add(megaAdd, getSize);
                    }
                    else
                    {
                        var @var = Expression.Variable(members[i].GetUnderlyingType());
                        variables.Add(var);
                        list.Add(Expression.Assign(var, Expression.PropertyOrField(item, members[i].Name)));

                        var getSize = BuildGetSize(var, charSize, membersOrder, allowNull, depth + 1);
                        megaAdd = (i == 0) ? getSize : Expression.Add(megaAdd, getSize);
                    }
                }

                if (!canBeNull || type.IsStruct())
                {
                    if (list.Count == 0)
                    {
                        return(megaAdd);
                    }

                    list.Add(Expression.Label(Expression.Label(typeof(int)), megaAdd));

                    return(Expression.Block(variables, list));
                }

                if (variables.Count == 0)
                {
                    return(Expression.Block(
                               Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)),
                                                    Expression.Add(Expression.Constant(1), megaAdd),

                                                    Expression.Constant(1)
                                                    )));
                }

                list.Add(Expression.Label(Expression.Label(typeof(int)), Expression.Add(Expression.Constant(1), megaAdd)));

                return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)),
                                            Expression.Block(variables, list),
                                            Expression.Constant(1)
                                            ));
            }

            throw new NotSupportedException(item.Type.ToString());
        }
Beispiel #14
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) && IsNumberType(type2))
            {
                return(Expression.Assign(Value1, Expression.Convert(Value2, type1)));
            }

            if (type1.IsKeyValuePair())
            {
                var key   = Expression.Variable(type1.GetGenericArgument(0));
                var value = Expression.Variable(type1.GetGenericArgument(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.GetGenericArgument(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.GetGenericArgument(0)) && type1.GetGenericArgument(0) == typeof(Guid))
                {
                    throw new NotSupportedException(String.Format("Dictionary<{0}, TValue>", type1.GetGenericArgument(0)));
                }

                var key   = Expression.Variable(type1.GetGenericArgument(0));
                var value = Expression.Variable(type1.GetGenericArgument(1));

                var block = Expression.Block(new ParameterExpression[] { key, value },
                                             Expression.Assign(Value1, type2.GetGenericArgument(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 constructParam = Expression.PropertyOrField(data2Var, type2.IsNullable() ? "Value" : DataTypeUtils.GetPublicMembers(type2, membersOrder2).First().Name);

                var block = Expression.Block(new ParameterExpression[] { data1Var, data2Var },
                                             Expression.Assign(data2Var, Value2),
                                             Expression.Assign(data1Var, Expression.New(
                                                                   type1.GetConstructor(new Type[] { type1.GetGenericArgument(0) }),
                                                                   constructParam.GetType() == type1.GetGenericArgument(0) ?
                                                                   (Expression)constructParam :
                                                                   (Expression)Expression.Convert(constructParam, type1.GetGenericArgument(0)))),
                                             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());
        }
Beispiel #15
0
        public static bool CheckCompatible(Type type1, Type type2, HashSet <Type> cycleCheck, Func <Type, MemberInfo, int> membersOrder1 = null, Func <Type, MemberInfo, int> membersOrder2 = null)
        {
            if (type1 == typeof(Guid) || type1 == typeof(byte[]))
            {
                return(type2 == typeof(Guid) || type2 == typeof(byte[]));
            }

            if (type1.IsEnum() || type2.IsEnum())
            {
                return((type1.IsEnum() && type2.IsEnum()) || (IsIntegerType(type1) || IsIntegerType(type2)));
            }

            if (DataType.IsPrimitiveType(type1))
            {
                return((type1 == type2) || (IsNumberType(type1) && IsNumberType(type2)));
            }

            if (type1.IsArray)
            {
                return(CheckCompatible(type1.GetElementType(), type2.GetElementType(), cycleCheck, membersOrder1, membersOrder2));
            }

            if (type1.IsList())
            {
                return(CheckCompatible(type1.GetGenericArgument(0), type2.GetGenericArgument(0), cycleCheck, membersOrder1, membersOrder2));
            }

            if (type1.IsDictionary())
            {
                return(CheckCompatible(type1.GetGenericArgument(0), type2.GetGenericArgument(0), cycleCheck, membersOrder1, membersOrder2) && CheckCompatible(type1.GetGenericArgument(1), type2.GetGenericArgument(1), cycleCheck, membersOrder1, membersOrder2));
            }

            if (type1.IsClass() || type1.IsStruct())
            {
                List <Type> type1Slotes = new List <Type>();
                List <Type> type2Slotes = new List <Type>();

                if (type1.IsNullable())
                {
                    type1Slotes.Add(type1.GetGenericArgument(0));
                }

                if (type2.IsNullable())
                {
                    type2Slotes.Add(type2.GetGenericArgument(0));
                }

                if (type1.IsKeyValuePair())
                {
                    type1Slotes.Add(type1.GetGenericArgument(0));
                    type1Slotes.Add(type1.GetGenericArgument(1));
                }

                if (type2.IsKeyValuePair())
                {
                    type2Slotes.Add(type2.GetGenericArgument(0));
                    type2Slotes.Add(type2.GetGenericArgument(1));
                }

                foreach (var slote in DataTypeUtils.GetPublicMembers(type1, membersOrder1))
                {
                    type1Slotes.Add(slote.GetUnderlyingType());
                }

                foreach (var slote in DataTypeUtils.GetPublicMembers(type2, membersOrder2))
                {
                    type2Slotes.Add(slote.GetUnderlyingType());
                }

                if (type1Slotes.Count != type2Slotes.Count)
                {
                    return(false);
                }

                for (int i = 0; i < type1Slotes.Count; i++)
                {
                    if (cycleCheck.Contains(type1Slotes[i]))
                    {
                        throw new NotSupportedException(String.Format("Type {0} has cycle declaration.", type1Slotes[i]));
                    }

                    cycleCheck.Add(type1Slotes[i]);
                    if (!CheckCompatible(type1Slotes[i], type2Slotes[i], cycleCheck, membersOrder1, membersOrder2))
                    {
                        return(false);
                    }
                    cycleCheck.Remove(type1Slotes[i]);
                }

                return(true);
            }

            throw new NotSupportedException(type2.ToString());
        }
Beispiel #16
0
        internal static Expression CreateStoreBody(Type type, IIndexerPersist[] persists, Expression writer, Expression callValues, ParameterExpression idx, Expression count, Func <Type, MemberInfo, int> membersOrder)
        {
            List <Expression> list = new List <Expression>();
            int itemsCount         = DataTypeUtils.GetPublicMembers(type, membersOrder).Count();

            //Create body for single item.
            if (itemsCount <= 1)
            {
                var persist = Expression.Convert(Expression.Constant(persists[0]), persists[0].GetType());
                var ms      = Expression.Variable(typeof(MemoryStream), "ms");
                var func    = Expression.Lambda(itemsCount == 0 ? callValues : Expression.PropertyOrField(callValues, DataTypeUtils.GetPublicMembers(type, membersOrder).First().Name), idx);

                return(ms.Using(Expression.Block(
                                    Expression.Assign(ms, Expression.New(typeof(MemoryStream).GetConstructor(new Type[] { }))),
                                    Expression.Call(persist, persist.Type.GetMethod("Store"), Expression.New(typeof(BinaryWriter).GetConstructor(new Type[] { typeof(MemoryStream) }), ms), func, count),
                                    Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.ConvertChecked(Expression.Property(ms, "Length"), typeof(ulong))),
                                    Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(byte[]), typeof(int), typeof(int) }),
                                                    Expression.Call(ms, typeof(MemoryStream).GetMethod("GetBuffer")), Expression.Constant(0), Expression.Convert(Expression.Property(ms, "Length"), typeof(int)))
                                    )));
            }
            else
            {
                var streams = Expression.Variable(typeof(MemoryStream[]), "streams");
                var actions = Expression.Variable(typeof(Action[]), "actions");

                list.Add(Expression.Assign(streams, Expression.New(typeof(MemoryStream[]).GetConstructor(new Type[] { typeof(int) }), Expression.Constant(itemsCount, typeof(int)))));
                list.Add(Expression.Assign(actions, Expression.New(typeof(Action[]).GetConstructor(new Type[] { typeof(int) }), Expression.Constant(itemsCount, typeof(int)))));

                int counter = 0;
                foreach (var member in DataTypeUtils.GetPublicMembers(type, membersOrder))
                {
                    var persist = Expression.Convert(Expression.Constant(persists[counter]), persists[counter].GetType());
                    var ms      = Expression.ArrayAccess(streams, Expression.Constant(counter, typeof(int)));
                    var func    = Expression.Lambda(Expression.PropertyOrField(callValues, member.Name), idx);

                    var writerNew = Expression.New(typeof(BinaryWriter).GetConstructor(new Type[] { typeof(MemoryStream) }), ms);

                    var action = Expression.Lambda(Expression.Block(
                                                       Expression.Assign(ms, Expression.New(typeof(MemoryStream).GetConstructor(new Type[] { }))),
                                                       Expression.Call(persist, persist.Type.GetMethod("Store"), writerNew, func, count)
                                                       ));

                    list.Add(Expression.Assign(Expression.ArrayAccess(actions, Expression.Constant(counter)), action));
                    counter++;
                }

                list.Add(Expression.Call(typeof(Parallel).GetMethod("Invoke", new Type[] { typeof(Action[]) }), actions));

                list.Add(streams.For(
                             (i) =>
                {
                    var stream = Expression.Variable(typeof(MemoryStream), "stream");

                    return(stream.Using(Expression.Block(
                                            Expression.Assign(stream, Expression.ArrayAccess(streams, i)),
                                            Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.ConvertChecked(Expression.Property(stream, "Length"), typeof(ulong))),
                                            Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(byte[]), typeof(int), typeof(int) }),
                                                            Expression.Call(stream, typeof(MemoryStream).GetMethod("GetBuffer")), Expression.Constant(0), Expression.Convert(Expression.Property(stream, "Length"), typeof(int)))
                                            )));
                },
                             Expression.Label()
                             ));

                return(Expression.Block(new ParameterExpression[] { actions, streams }, list));
            }
        }
Beispiel #17
0
        private static Expression BuildRead(Expression reader, Type itemType, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth)
        {
            bool canBeNull = CanBeNull(itemType, allowNull, depth);

            if (itemType == typeof(Guid))
            {
                return(Expression.New(itemType.GetConstructor(new Type[] { typeof(byte[]) }), GetReadCommand(reader, typeof(byte[]), canBeNull)));
            }

            if (itemType.IsEnum())
            {
                return(Expression.Convert(GetReadCommand(reader, itemType.GetEnumBaseType(), canBeNull), itemType));
            }

            if (DataType.IsPrimitiveType(itemType))
            {
                return(GetReadCommand(reader, itemType, canBeNull));
            }

            if (itemType.IsKeyValuePair())
            {
                return(Expression.New(
                           itemType.GetConstructor(new Type[] { itemType.GetGenericArgument(0), itemType.GetGenericArgument(1) }),
                           BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1), BuildRead(reader, itemType.GetGenericArgument(1), membersOrder, allowNull, depth + 1)
                           ));
            }

            if (itemType.IsArray || itemType.IsList() || itemType.IsDictionary())
            {
                var field  = Expression.Variable(itemType);
                var lenght = Expression.Variable(typeof(int));

                var block = Expression.Block(
                    Expression.Assign(lenght, Expression.Convert(Expression.Call(typeof(CountCompression).GetMethod("Deserialize"), reader), typeof(int))),
                    itemType.IsDictionary() && itemType.GetGenericArgument(0) == typeof(byte[]) ?
                    Expression.Assign(field, Expression.New(field.Type.GetConstructor(new Type[] { typeof(int), typeof(IEqualityComparer <byte[]>) }), lenght, Expression.Field(null, typeof(BigEndianByteArrayEqualityComparer), "Instance"))) :
                    Expression.Assign(field, Expression.New(field.Type.GetConstructor(new Type[] { typeof(int) }), lenght)),
                    field.For(i =>
                {
                    if (itemType.IsArray)
                    {
                        return(Expression.Assign(Expression.ArrayAccess(field, i), BuildRead(reader, itemType.GetElementType(), membersOrder, allowNull, depth + 1)));
                    }
                    else if (itemType.IsList())
                    {
                        return(Expression.Call(field, field.Type.GetMethod("Add"), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1)));
                    }
                    else     //if (dataType.IsDictionary)
                    {
                        var keyType = itemType.GetGenericArgument(0);

                        if (!IsSupportDictionaryKeyType(keyType))
                        {
                            throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", keyType.ToString()));
                        }

                        return(Expression.Call(field, field.Type.GetMethod("Add"),
                                               BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1),
                                               BuildRead(reader, itemType.GetGenericArgument(1), membersOrder, allowNull, depth + 1)
                                               ));
                    }
                },
                              Expression.Label(), lenght)
                    );

                if (canBeNull)
                {
                    return(Expression.Block(field.Type, new ParameterExpression[] { field, lenght },
                                            Expression.IfThenElse(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")),
                                                                  block,
                                                                  Expression.Assign(field, Expression.Constant(null, field.Type))),
                                            Expression.Label(Expression.Label(field.Type), field)));
                }

                return(Expression.Block(field.Type, new ParameterExpression[] { field, lenght },
                                        block,
                                        Expression.Label(Expression.Label(field.Type), field)));
            }

            if (itemType.IsNullable())
            {
                if (!canBeNull)
                {
                    return(Expression.New(itemType.GetConstructor(new Type[] { itemType.GetGenericArgument(0) }), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1)));
                }

                return(Expression.Condition(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")),
                                            Expression.New(itemType.GetConstructor(new Type[] { itemType.GetGenericArgument(0) }), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1)),
                                            Expression.Constant(null, itemType)));
            }

            if (itemType.IsClass() || itemType.IsStruct())
            {
                var item = Expression.Variable(itemType);

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

                foreach (var member in DataTypeUtils.GetPublicMembers(itemType, membersOrder))
                {
                    list.Add(Expression.Assign(Expression.PropertyOrField(item, member.Name), BuildRead(reader, member.GetUnderlyingType(), membersOrder, allowNull, depth + 1)));
                }

                if (!canBeNull)
                {
                    list.Add(Expression.Label(Expression.Label(item.Type), item));
                    return(Expression.Block(item.Type, new ParameterExpression[] { item }, list));
                }

                return(Expression.Block(itemType, new ParameterExpression[] { item },
                                        Expression.IfThenElse(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")),
                                                              Expression.Block(list),
                                                              Expression.Assign(item, Expression.Constant(null, itemType))),
                                        Expression.Label(Expression.Label(item.Type), item)));
            }

            throw new ArgumentException(itemType.ToString());
        }
Beispiel #18
0
        private static Expression BuildWrite(Expression item, Expression writer, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth)
        {
            var  type      = item.Type;
            bool canBeNull = CanBeNull(type, allowNull, depth);

            if (type == typeof(Guid))
            {
                return(GetWriteCommand(writer, Expression.Call(item, type.GetMethod("ToByteArray")), canBeNull));
            }

            if (type.IsEnum())
            {
                return(GetWriteCommand(writer, Expression.Convert(item, item.Type.GetEnumBaseType()), canBeNull));
            }

            if (DataType.IsPrimitiveType(type))
            {
                return(GetWriteCommand(writer, item, canBeNull));
            }

            if (type.IsKeyValuePair())
            {
                return(Expression.Block(
                           BuildWriteAssignedOrCurrent(Expression.PropertyOrField(item, "Key"), writer, membersOrder, allowNull, depth + 1),
                           BuildWriteAssignedOrCurrent(Expression.PropertyOrField(item, "Value"), writer, membersOrder, allowNull, depth + 1)
                           ));
            }

            if (type.IsArray || type.IsList())
            {
                if (!canBeNull)
                {
                    return(Expression.Block(Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(type.IsArray ? (Expression)Expression.ArrayLength(item) : Expression.Property(item, "Count"), typeof(ulong))),
                                            item.For(i =>
                                                     BuildWriteAssignedOrCurrent(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), writer, membersOrder, allowNull, depth + 1),
                                                     Expression.Label())));
                }

                return(Expression.IfThenElse(Expression.NotEqual(item, Expression.Constant(null)),
                                             Expression.Block(
                                                 Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(true)),
                                                 Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(type.IsArray ? (Expression)Expression.ArrayLength(item) : Expression.Property(item, "Count"), typeof(ulong))),
                                                 item.For(i =>
                                                          BuildWriteAssignedOrCurrent(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), writer, membersOrder, allowNull, depth + 1),
                                                          Expression.Label())),
                                             Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false))
                                             ));
            }

            if (type.IsDictionary())
            {
                var keyType = type.GetGenericArgument(0);

                if (!IsSupportDictionaryKeyType(keyType))
                {
                    throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", keyType.ToString()));
                }

                if (!canBeNull)
                {
                    return(Expression.Block(
                               Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(Expression.Property(item, "Count"), typeof(ulong))),
                               item.ForEach(current =>
                    {
                        var kv = Expression.Variable(current.Type);

                        return Expression.Block(new ParameterExpression[] { kv },
                                                Expression.Assign(kv, current),
                                                BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Key"), writer, membersOrder, allowNull, depth + 1),
                                                BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Value"), writer, membersOrder, allowNull, depth + 1)
                                                );
                    }, Expression.Label())
                               ));
                }

                return(Expression.IfThenElse(Expression.NotEqual(item, Expression.Constant(null)),
                                             Expression.Block(
                                                 Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(true)),
                                                 Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(Expression.Property(item, "Count"), typeof(ulong))),
                                                 item.ForEach(current =>
                {
                    var kv = Expression.Variable(current.Type);

                    return Expression.Block(new ParameterExpression[] { kv },
                                            Expression.Assign(kv, current),
                                            BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Key"), writer, membersOrder, allowNull, depth + 1),
                                            BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Value"), writer, membersOrder, allowNull, depth + 1)
                                            );
                }, Expression.Label())),
                                             Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false))
                                             ));
            }

            if (type.IsNullable())
            {
                if (!canBeNull)
                {
                    return(BuildWrite(Expression.PropertyOrField(item, "Value"), writer, membersOrder, allowNull, depth + 1));
                }

                return(Expression.Block(
                           Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.PropertyOrField(item, "HasValue")),
                           Expression.IfThen(Expression.PropertyOrField(item, "HasValue"),
                                             BuildWrite(Expression.PropertyOrField(item, "Value"), writer, membersOrder, allowNull, depth + 1))));
            }

            if (type.IsClass() || type.IsStruct())
            {
                List <ParameterExpression> variables = new List <ParameterExpression>();
                List <Expression>          list      = new List <Expression>();

                if (canBeNull)
                {
                    list.Add(Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(true)));
                }

                var members = DataTypeUtils.GetPublicMembers(type, membersOrder).ToList();

                for (int i = 0; i < members.Count; i++)
                {
                    var member     = members[i];
                    var memberType = member.GetUnderlyingType();

                    if (DataType.IsPrimitiveType(memberType) || memberType.IsKeyValuePair())
                    {
                        list.Add(BuildWrite(Expression.PropertyOrField(item, member.Name), writer, membersOrder, allowNull, depth + 1));
                    }
                    else
                    {
                        var @var = Expression.Variable(member.GetUnderlyingType());
                        variables.Add(var);
                        list.Add(Expression.Assign(var, Expression.PropertyOrField(item, member.Name)));
                        list.Add(BuildWrite(var, writer, membersOrder, allowNull, depth + 1));
                    }
                }

                if (!canBeNull)
                {
                    return(Expression.Block(variables, list));
                }

                return(Expression.IfThenElse(Expression.NotEqual(item, Expression.Constant(null)),
                                             Expression.Block(variables, list),
                                             Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false))
                                             ));
            }

            throw new NotSupportedException(item.Type.ToString());
        }