private static object ReadArray(BinaryReader reader, bool isNull, out Type objectType)
        {
            var  elemObjType = (ObjectTypeCode)reader.ReadByte();
            Type elementType;

            if (elemObjType == ObjectTypeCode.Primitive)
            {
                var primitiveTypeCode = (PrimitiveTypeCode)reader.ReadByte();
                elementType = SerializerUtil.GetObjectType(primitiveTypeCode);
            }
            else if (elemObjType == ObjectTypeCode.Serializable)
            {
                var typeName = reader.ReadString();
                elementType = Type.GetType(typeName, true, true);
            }
            else
            {
                throw new NotSupportedException();
            }

            objectType = elementType.MakeArrayType();

            if (isNull)
            {
                return(null);
            }

            var length = reader.ReadInt32();
            var array  = Array.CreateInstance(elementType, length);

            for (int i = 0; i < length; i++)
            {
                Type itemType;
                var  item = ReadObject(reader, out itemType);

                if (!elementType.GetTypeInfo().IsAssignableFrom(itemType.GetTypeInfo()))
                {
                    throw new SerializationException();
                }

                array.SetValue(item, i);
            }

            return(array);
        }
        private static Type ReadGenericArgumentType(BinaryReader reader)
        {
            var objTypeCode = (ObjectTypeCode)reader.ReadByte();

            switch (objTypeCode)
            {
            case ObjectTypeCode.Primitive: {
                var nullable          = reader.ReadBoolean();
                var primitiveTypeCode = (PrimitiveTypeCode)reader.ReadByte();
                var primitiveType     = SerializerUtil.GetObjectType(primitiveTypeCode);
                return(nullable ? typeof(Nullable <>).MakeGenericType(primitiveType) : primitiveType);
            }

            case ObjectTypeCode.Serializable:
                return(Type.GetType(reader.ReadString(), true, true));

            case ObjectTypeCode.Object:
                return(typeof(object));

            default:
                throw new NotSupportedException();
            }
        }
        private static object ReadPrimitive(BinaryReader reader, bool isNull, out Type objectType)
        {
            var nullable = reader.ReadBoolean();
            var typeCode = (PrimitiveTypeCode)reader.ReadByte();

            objectType = SerializerUtil.GetObjectType(typeCode);

            if (nullable)
            {
                objectType = typeof(Nullable <>).MakeGenericType(objectType);
            }

            if (isNull)
            {
                return(null);
            }

            switch (typeCode)
            {
            case PrimitiveTypeCode.Boolean:
                return(reader.ReadBoolean());

            case PrimitiveTypeCode.Byte:
                return(reader.ReadByte());

            case PrimitiveTypeCode.SByte:
                return(reader.ReadSByte());

            case PrimitiveTypeCode.Int16:
                return(reader.ReadInt16());

            case PrimitiveTypeCode.UInt16:
                return(reader.ReadUInt16());

            case PrimitiveTypeCode.Int32:
                return(reader.ReadInt32());

            case PrimitiveTypeCode.UInt32:
                return(reader.ReadUInt32());

            case PrimitiveTypeCode.Int64:
                return(reader.ReadInt64());

            case PrimitiveTypeCode.UInt64:
                return(reader.ReadUInt64());

            case PrimitiveTypeCode.Single:
                return(reader.ReadSingle());

            case PrimitiveTypeCode.Double:
                return(reader.ReadDouble());

            case PrimitiveTypeCode.Char:
                return(reader.ReadChar());

            case PrimitiveTypeCode.String:
                return(reader.ReadString());

            default:
                throw new SerializationException();
            }
        }