Пример #1
0
        private static ValueWriter GenerateFieldInfoSerializer(Serializer serializer, FieldInfo field)
        {
            if (serializer == null)
            {
                throw new ArgumentNullException(nameof(serializer));
            }

            if (field == null)
            {
                throw new ArgumentNullException(nameof(field));
            }

            //get the serializer for the type of the field
            var valueSerializer = serializer.GetSerializerByType(field.FieldType);
            //runtime generate a delegate that reads the content of the given field
            var getFieldValue = GenerateFieldInfoReader(field);

            //if the type is one of our special primitives, ignore manifest as the content will always only be of this type
            if (!serializer.Options.VersionTolerance && Serializer.IsPrimitiveType(field.FieldType))
            {
                //primitive types does not need to write any manifest, if the field type is known
                //nor can they be null (StringSerializer has it's own null handling)
                ValueWriter fieldWriter = (stream, o, session) =>
                {
                    var value = getFieldValue(o);
                    valueSerializer.WriteValue(stream, value, session);
                };
                return(fieldWriter);
            }
            else
            {
                var valueType = field.FieldType;
                if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    var nullableType = field.FieldType.GetGenericArguments()[0];
                    valueSerializer = serializer.GetSerializerByType(nullableType);
                    valueType       = nullableType;
                }
                var preserveObjectReferences = serializer.Options.PreserveObjectReferences;

                ValueWriter fieldWriter = (stream, o, session) =>
                {
                    var value = getFieldValue(o);

                    stream.WriteObject(value, valueType, valueSerializer, preserveObjectReferences, session);
                };
                return(fieldWriter);
            }
        }
Пример #2
0
        private static Action <Stream, object, DeserializerSession> GenerateFieldInfoDeserializer(Serializer serializer,
                                                                                                  Type type, FieldInfo field)
        {
            if (serializer == null)
            {
                throw new ArgumentNullException(nameof(serializer));
            }

            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (field == null)
            {
                throw new ArgumentNullException(nameof(field));
            }

            var s = serializer.GetSerializerByType(field.FieldType);

            Action <object, object> setter;

            if (field.IsInitOnly)
            {
                setter = field.SetValue;
            }
            else
            {
                var targetExp = Parameter(typeof(object), "target");
                var valueExp  = Parameter(typeof(object), "value");

                // ReSharper disable once PossibleNullReferenceException
                Expression castTartgetExp = field.DeclaringType.IsValueType
                    ? Unbox(targetExp, type)
                    : Convert(targetExp, type);
                Expression castValueExp = Convert(valueExp, field.FieldType);
                var        fieldExp     = Field(castTartgetExp, field);
                var        assignExp    = Assign(fieldExp, castValueExp);
                setter = Lambda <Action <object, object> >(assignExp, targetExp, valueExp).Compile();
            }


            if (!serializer.Options.VersionTolerance && Serializer.IsPrimitiveType(field.FieldType))
            {
                //Only optimize if property names are not included.
                //if they are included, we need to be able to skip past unknown property data
                //e.g. if sender have added a new property that the receiveing end does not yet know about
                //which we cannot do w/o a manifest
                Action <Stream, object, DeserializerSession> fieldReader = (stream, o, session) =>
                {
                    var value = s.ReadValue(stream, session);
                    setter(o, value);
                };
                return(fieldReader);
            }
            else
            {
                Action <Stream, object, DeserializerSession> fieldReader = (stream, o, session) =>
                {
                    var value = stream.ReadObject(session);
                    setter(o, value);
                };
                return(fieldReader);
            }
        }
Пример #3
0
        private ObjectReader GetFieldsReader([NotNull] Serializer serializer, [NotNull] IEnumerable <FieldInfo> fields,
                                             [NotNull] Type type)
        {
            var c                       = new Compiler <ObjectReader>();
            var stream                  = c.Parameter <Stream>("stream");
            var session                 = c.Parameter <DeserializerSession>("session");
            var newExpression           = c.NewObject(type);
            var target                  = c.Variable <object>("target");
            var assignNewObjectToTarget = c.WriteVar(target, newExpression);

            c.Emit(assignNewObjectToTarget);

            if (serializer.Options.PreserveObjectReferences)
            {
                var trackDeserializedObjectMethod =
                    typeof(DeserializerSession)
                    .GetMethod(nameof(DeserializerSession.TrackDeserializedObject));

                c.EmitCall(trackDeserializedObjectMethod, session, target);
            }

            //for (var i = 0; i < storedFieldCount; i++)
            //{
            //    var fieldName = stream.ReadLengthEncodedByteArray(session);
            //    if (!Utils.Compare(fieldName, fieldNames[i]))
            //    {
            //        //TODO: field name mismatch
            //        //this should really be a compare less equal or greater
            //        //to know if the field is added or removed

            //        //1) if names are equal, read the value and assign the field

            //        //2) if the field is less than the expected field, then this field is an unknown new field
            //        //we need to read this object and just ignore its content.

            //        //3) if the field is greater than the expected, we need to check the next expected until
            //        //the current is less or equal, then goto 1)
            //    }
            //}

            var typedTarget = c.CastOrUnbox(target, type);
            var fieldsArray = fields.ToArray();
            var serializers = fieldsArray.Select(field => serializer.GetSerializerByType(field.FieldType)).ToArray();

            var preallocatedBufferSize = serializers.Length != 0
                ? serializers.Max(s => s.PreallocatedByteBufferSize)
                : 0;

            if (preallocatedBufferSize > 0)
            {
                EmitPreallocatedBuffer(c, preallocatedBufferSize, session,
                                       typeof(DeserializerSession).GetMethod(nameof(DeserializerSession.GetBuffer)));
            }

            for (var i = 0; i < fieldsArray.Length; i++)
            {
                var field = fieldsArray[i];
                var s     = serializers[i];

                int read;
                if (!serializer.Options.VersionTolerance && field.FieldType.IsWirePrimitive())
                {
                    //Only optimize if property names are not included.
                    //if they are included, we need to be able to skip past unknown property data
                    //e.g. if sender have added a new property that the receiveing end does not yet know about
                    //which we cannot do w/o a manifest
                    read = s.EmitReadValue(c, stream, session, field);
                }
                else
                {
                    var method = typeof(StreamEx).GetMethod(nameof(StreamEx.ReadObject));
                    read = c.StaticCall(method, stream, session);
                    read = c.Convert(read, field.FieldType);
                }


                var assignReadToField = c.WriteField(field, typedTarget, read);
                c.Emit(assignReadToField);
            }
            c.Emit(target);

            var readAllFields = c.Compile();

            return(readAllFields);
        }
Пример #4
0
        private static Action <Stream, object, SerializerSession> GenerateFieldDeserializer(Serializer serializer,
                                                                                            Type type, FieldInfo field)
        {
            var s = serializer.GetSerializerByType(field.FieldType);

            Action <object, object> setter;

            if (field.IsInitOnly)
            {
                setter = field.SetValue;
            }
            else
            {
                ParameterExpression targetExp = Expression.Parameter(typeof(object), "target");
                ParameterExpression valueExp  = Expression.Parameter(typeof(object), "value");

                Expression castTartgetExp = field.DeclaringType.IsValueType
                    ? Expression.Unbox(targetExp, type)
                    : Expression.Convert(targetExp, type);
                Expression       castValueExp = Expression.Convert(valueExp, field.FieldType);
                MemberExpression fieldExp     = Expression.Field(castTartgetExp, field);
                BinaryExpression assignExp    = Expression.Assign(fieldExp, castValueExp);
                setter = Expression.Lambda <Action <object, object> >(assignExp, targetExp, valueExp).Compile();
            }


            if (!serializer.Options.VersionTolerance && Serializer.IsPrimitiveType(field.FieldType))
            {
                //Only optimize if property names are not included.
                //if they are included, we need to be able to skip past unknown property data
                //e.g. if sender have added a new property that the receiveing end does not yet know about
                //which we cannot do w/o a manifest
                Action <Stream, object, SerializerSession> fieldReader = (stream, o, session) =>
                {
                    var value = s.ReadValue(stream, session);
                    setter(o, value);
                    //var x = field.GetValue(o);
                    //if (value != null && !value.Equals(x))
                    //{

                    //}
                    //     field.SetValue(o, value);
                };
                return(fieldReader);
            }
            else
            {
                Action <Stream, object, SerializerSession> fieldReader = (stream, o, session) =>
                {
                    var value = stream.ReadObject(session);
                    //   field.SetValue(o, value);
                    setter(o, value);
                    //var x = field.GetValue(o);
                    //if (value != null && !value.Equals(x))
                    //{

                    //}
                };
                return(fieldReader);
            }
        }
Пример #5
0
        //this generates a FieldWriter that writes all fields by unrolling all fields and calling them individually
        //no loops involved
        private ObjectWriter GetFieldsWriter([NotNull] Serializer serializer, [NotNull] IEnumerable <FieldInfo> fields,
                                             out int preallocatedBufferSize)
        {
            var c = new Compiler <ObjectWriter>();

            var stream             = c.Parameter <Stream>("stream");
            var target             = c.Parameter <object>("target");
            var session            = c.Parameter <SerializerSession>("session");
            var preserveReferences = c.Constant(serializer.Options.PreserveObjectReferences);

            if (serializer.Options.PreserveObjectReferences)
            {
                var method =
                    typeof(SerializerSession).GetMethod(nameof(SerializerSession.TrackSerializedObject));

                c.EmitCall(method, session, target);
            }

            var fieldsArray = fields.ToArray();
            var serializers = fieldsArray.Select(field => serializer.GetSerializerByType(field.FieldType)).ToArray();

            preallocatedBufferSize = serializers.Length != 0 ? serializers.Max(s => s.PreallocatedByteBufferSize) : 0;

            if (preallocatedBufferSize > 0)
            {
                EmitPreallocatedBuffer(c, preallocatedBufferSize, session,
                                       typeof(SerializerSession).GetMethod("GetBuffer"));
            }

            for (var i = 0; i < fieldsArray.Length; i++)
            {
                var field = fieldsArray[i];
//get the serializer for the type of the field
                var valueSerializer = serializers[i];
                //runtime Get a delegate that reads the content of the given field

                var cast      = c.CastOrUnbox(target, field.DeclaringType);
                var readField = c.ReadField(field, cast);

                //if the type is one of our special primitives, ignore manifest as the content will always only be of this type
                if (!serializer.Options.VersionTolerance && field.FieldType.IsWirePrimitive())
                {
                    //primitive types does not need to write any manifest, if the field type is known
                    valueSerializer.EmitWriteValue(c, stream, readField, session);
                }
                else
                {
                    var converted = c.Convert <object>(readField);
                    var valueType = field.FieldType;
                    if (field.FieldType.IsNullable())
                    {
                        var nullableType = field.FieldType.GetNullableElement();
                        valueSerializer = serializer.GetSerializerByType(nullableType);
                        valueType       = nullableType;
                    }

                    var vs = c.Constant(valueSerializer);
                    var vt = c.Constant(valueType);

                    var method = typeof(StreamEx).GetMethod(nameof(StreamEx.WriteObject));

                    c.EmitStaticCall(method, stream, converted, vt, vs, preserveReferences, session);
                }
            }

            return(c.Compile());
        }