Example #1
0
 /// <summary>
 /// Returns a hash code for this instance.
 /// </summary>
 /// <returns>
 /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
 /// </returns>
 public override int GetHashCode()
 {
     unchecked
     {
         int hashCode = 17 + AllowNull.GetHashCode() ^ ReadOnly.GetHashCode() + 31 * GetHashCode(PossibleValues);;
         return((DefaultValue == null) ? hashCode : hashCode *32 ^ DefaultValue.GetHashCode());
     }
 }
Example #2
0
        public Persist(Func <Type, MemberInfo, int> membersOrder = null, AllowNull allowNull = AllowNull.None)
        {
            Type         = typeof(T);
            MembersOrder = membersOrder;
            AllowNull    = allowNull;

            write = CreateWriteMethod().Compile();
            read  = CreateReadMethod().Compile();
        }
Example #3
0
        public DataPersistSize(Type type, int charSize, AllowNull allowNull = AllowNull.None, Func <Type, MemberInfo, int> membersOrder = null)
        {
            Type = type;

            CharSize     = charSize;
            AllowNull    = allowNull;
            MembersOrder = membersOrder;

            getSize = CreateGetSizeMethod().Compile();
        }
Example #4
0
        public DataPersist(Type type, Func <Type, MemberInfo, int> membersOrder = null, AllowNull allowNull = AllowNull.None)
        {
            Type = type;

            MembersOrder = membersOrder;
            AllowNull    = allowNull;

            LambdaWrite = CreateWriteMethod();
            write       = LambdaWrite.Compile();

            LambdaRead = CreateReadMethod();
            read       = LambdaRead.Compile();
        }
Example #5
0
        private static bool CanBeNull(Type type, AllowNull allowNull, int depth)
        {
            //if (type == typeof(Guid))
            //    return false;

            if (type.IsEnum())
            {
                return(false);
            }

            if (type.IsStruct() && !type.IsNullable())
            {
                return(false);
            }

            if (allowNull == AllowNull.OnlyMembers)
            {
                return(depth > 0);
            }

            return(allowNull == AllowNull.All);
        }
Example #6
0
 public static Expression CreateReadBody(Expression reader, Type itemType, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull)
 {
     return(BuildRead(reader, itemType, membersOrder, allowNull, 0));
 }
Example #7
0
        private static Expression BuildGetSizeWithAssignedOrCurrentVariable(Expression variable, int charSize, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth)
        {
            var type = variable.Type;

            if (DataType.IsPrimitiveType(type) && type.IsEnum() && type != typeof(Guid))
            {
                return(BuildGetSize(variable, charSize, membersOrder, allowNull, depth + 1));
            }

            ParameterExpression @var = Expression.Variable(type);

            return(Expression.Block(new ParameterExpression[] { @var },
                                    Expression.Assign(@var, variable),

                                    Expression.Label(Expression.Label(typeof(int)), BuildGetSize(@var, charSize, membersOrder, allowNull, depth + 1))
                                    ));
        }
Example #8
0
        public static Expression CreateReadBody(Expression reader, Type itemType, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull)
        {
            var item = Expression.Variable(itemType);

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

            if (DataType.IsPrimitiveType(itemType) || itemType.IsEnum || itemType == typeof(Guid) || itemType.IsKeyValuePair() || itemType.IsArray || itemType.IsList() || itemType.IsDictionary() || itemType.IsNullable())
            {
                return(BuildRead(reader, itemType, membersOrder, allowNull, true));
            }
            else
            {
                list.Add(Expression.Assign(item, Expression.New(itemType)));

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

                list.Add(Expression.Label(Expression.Label(itemType), item));

                if (allowNull == AllowNull.All && !itemType.IsStruct())
                {
                    return(Expression.Condition(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")),
                                                Expression.Block(itemType, new ParameterExpression[] { item }, list), Expression.Label(Expression.Label(itemType),
                                                                                                                                       Expression.Constant(null, item.Type))));
                }
            }

            return(Expression.Block(itemType, new ParameterExpression[] { item }, list));
        }
Example #9
0
 public DataPersistSize(Type type, AllowNull allowNull = AllowNull.None, Func <Type, MemberInfo, int> membersOrder = null)
     : this(type, 1, allowNull, membersOrder)
 {
 }
Example #10
0
 public bool IsNullable()
 {
     return(AllowNull.ToLower() == Nullable.ToLower() && TypeHelper.SqlServerType2CSharpType(DataType).ToLower() != String.ToLower());
 }
Example #11
0
 public string this[AllowNull] string returnValue]
Example #12
0
 public string this[AllowNull] string allowNull, int? nullableInt, string optional = null]
Example #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());
        }
Example #14
0
 public static Expression CreateSizeBody(Expression item, int charSize, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull)
 {
     return(BuildGetSize(item, charSize, membersOrder, allowNull, 0));
 }
Example #15
0
        public static Expression CreateWriteBody(Expression item, Expression writer, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull)
        {
            List <Expression> list = new List <Expression>();

            if (DataType.IsPrimitiveType(item.Type) || item.Type.IsEnum || item.Type == typeof(Guid) || item.Type.IsKeyValuePair() || item.Type.IsArray || item.Type.IsList() || item.Type.IsDictionary() || item.Type.IsNullable())
            {
                list.Add(BuildWrite(item, writer, membersOrder, allowNull, true));
            }
            else
            {
                if (allowNull == AllowNull.All && !item.Type.IsStruct())
                {
                    list.Add(Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(true)));
                }

                foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder))
                {
                    list.Add(BuildWrite(Expression.PropertyOrField(item, member.Name), writer, membersOrder, allowNull, false));
                }

                if (allowNull == AllowNull.All && !item.Type.IsStruct())
                {
                    return(Expression.IfThenElse(Expression.NotEqual(item, Expression.Constant(null, item.Type)),
                                                 Expression.Block(list),
                                                 Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false))));
                }
            }

            return(Expression.Block(list));
        }
Example #16
0
        private static Expression BuildWrite(Expression item, Expression writer, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, bool isTop)
        {
            var  type      = item.Type;
            bool canBeNull = allowNull == AllowNull.All || (allowNull == AllowNull.OnlyMembers && !isTop);

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

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

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

            if (type.IsKeyValuePair())
            {
                return(Expression.Block(
                           BuildWrite(Expression.PropertyOrField(item, "Key"), writer, membersOrder, allowNull, false),
                           BuildWrite(Expression.PropertyOrField(item, "Value"), writer, membersOrder, allowNull, false)
                           ));
            }

            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 =>
                                                     WriteAssignedOrCurrentVariable(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), writer, membersOrder, allowNull),
                                                     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 =>
                                                          WriteAssignedOrCurrentVariable(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), writer, membersOrder, allowNull),
                                                          Expression.Label())),
                                             Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false))
                                             ));
            }

            if (type.IsDictionary())
            {
                if (!DataType.IsPrimitiveType(type.GetGenericArguments()[0]) && !type.GetGenericArguments()[0].IsEnum && type != typeof(Guid))
                {
                    throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", type.GetGenericArguments()[0].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),
                                                WriteAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Key"), writer, membersOrder, allowNull),
                                                WriteAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Value"), writer, membersOrder, allowNull)
                                                );
                    }, 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),
                                            WriteAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Key"), writer, membersOrder, allowNull),
                                            WriteAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Value"), writer, membersOrder, allowNull)
                                            );
                }, 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, false));
                }

                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, false))));
            }

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

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

                foreach (var member in DataTypeUtils.GetPublicMembers(type, membersOrder))
                {
                    if (DataType.IsPrimitiveType(type) || type.IsKeyValuePair())
                    {
                        list.Add(BuildWrite(Expression.PropertyOrField(item, member.Name), writer, membersOrder, allowNull, false));
                    }
                    else
                    {
                        var @var = Expression.Variable(member.GetPropertyOrFieldType());
                        variables.Add(var);
                        list.Add(Expression.Assign(var, Expression.PropertyOrField(item, member.Name)));
                        list.Add(BuildWrite(var, writer, membersOrder, allowNull, false));
                    }
                }

                if (!canBeNull || type.IsStruct())
                {
                    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());
        }
Example #17
0
 public static Expression CreateWriteBody(Expression item, Expression writer, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull)
 {
     return(BuildWrite(item, writer, membersOrder, allowNull, 0));
 }
Example #18
0
        private static Expression WriteAssignedOrCurrentVariable(Expression variable, Expression writer, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull)
        {
            var type = variable.Type;

            if (!DataType.IsPrimitiveType(type) && !type.IsEnum && type != typeof(Guid))
            {
                ParameterExpression _var = Expression.Variable(type);
                return(Expression.Block(new ParameterExpression[] { _var },
                                        Expression.Assign(_var, variable),
                                        BuildWrite(_var, writer, membersOrder, allowNull, false)));
            }

            return(BuildWrite(variable, writer, membersOrder, allowNull, false));
        }
Example #19
0
        private static Expression BuildWriteAssignedOrCurrent(Expression item, Expression writer, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth)
        {
            var type = item.Type;

            if (type == typeof(Guid) || type.IsEnum() || DataType.IsPrimitiveType(type))
            {
                return(BuildWrite(item, writer, membersOrder, allowNull, depth));
            }

            ParameterExpression @var = Expression.Variable(type);

            return(Expression.Block(new ParameterExpression[] { @var },
                                    Expression.Assign(@var, item),
                                    BuildWrite(@var, writer, membersOrder, allowNull, depth)));
        }
Example #20
0
        private static Expression BuildRead(Expression reader, Type itemType, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, bool isTop)
        {
            bool canBeNull = allowNull == AllowNull.All || (allowNull == AllowNull.OnlyMembers && !isTop);

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

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

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

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

            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.GetGenericArguments()[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, false)));
                    }
                    else if (itemType.IsList())
                    {
                        return(Expression.Call(field, field.Type.GetMethod("Add"), BuildRead(reader, itemType.GetGenericArguments()[0], membersOrder, allowNull, false)));
                    }
                    else         //if (dataType.IsDictionary)
                    {
                        return(Expression.Call(field, field.Type.GetMethod("Add"),
                                               BuildRead(reader, itemType.GetGenericArguments()[0], membersOrder, allowNull, false),
                                               BuildRead(reader, itemType.GetGenericArguments()[1], membersOrder, allowNull, false)
                                               ));
                    }
                },
                              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.GetGenericArguments()[0] }), BuildRead(reader, itemType.GetGenericArguments()[0], membersOrder, allowNull, false)));
                }

                return(Expression.Condition(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")),
                                            Expression.New(itemType.GetConstructor(new Type[] { itemType.GetGenericArguments()[0] }), BuildRead(reader, itemType.GetGenericArguments()[0], membersOrder, allowNull, false)),
                                            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.GetPropertyOrFieldType(), membersOrder, allowNull, false)));
                }

                if (!canBeNull || itemType.IsStruct())
                {
                    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());
        }
Example #21
0
 public PersistSize(AllowNull allowNull = AllowNull.None, Func <Type, MemberInfo, int> membersOrder = null)
     : this(1, allowNull, membersOrder)
 {
 }