コード例 #1
0
        // emits code to clear all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitClearFields(Type type, KnownSerializers serializers, ILGenerator il)
        {
            // simply invoke the type serializer for each relevant field
            foreach (FieldInfo field in GetClonableFields(type))
            {
                if (IsSimpleValueType(field.FieldType) || field.FieldType == typeof(string))
                {
                    continue;
                }

                // find the right handler
                var handler = serializers.GetUntypedHandler(field.FieldType);
                int index   = serializers.GetIndex(handler);

                // argument legend: 0 = ref target, 1 = context
                il.Emit(OpCodes.Ldarg_1);                         // push context
                il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                // handler.Clear(ref target.Field, context);
                // il.EmitWriteLine(string.Format("Clear(ref target.{0});", field.Name));
                il.Emit(OpCodes.Ldarg_0); // target
                if (type.IsClass)
                {
                    il.Emit(OpCodes.Ldind_Ref);
                }

                il.Emit(OpCodes.Ldflda, field); // target.field &
                il.Emit(OpCodes.Ldarg_1);       // context
                var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Clear), BindingFlags.Instance | BindingFlags.Public);
                il.Emit(OpCodes.Call, mi);
            }

            il.Emit(OpCodes.Ret);
        }
コード例 #2
0
ファイル: Generator.cs プロジェクト: yusharth/psi
        /// <summary>
        /// Determines whether an instance of the specified type must be cleared prior to reuse
        /// as a cloning or deserialization target.
        /// </summary>
        /// <param name="type">The type to check.</param>
        /// <param name="serializers">A registry of known serializers.</param>
        /// <returns>true if the type requires clearing prior to reuse; otherwise, false.</returns>
        internal static bool IsClearRequired(Type type, KnownSerializers serializers)
        {
            // first check whether a cached result exists
            var handler = serializers.GetUntypedHandler(type);

            if (handler.IsClearRequired.HasValue)
            {
                return(handler.IsClearRequired.Value);
            }

            // Initialize the cached value so that we know that we have seen it if we encounter it again during
            // the current evaluation (i.e. if the object graph contains a cycle back to the current type).
            handler.IsClearRequired = false;

            // Skip evaluation for simple value types and strings. Otherwise, clearing is only required
            // for Shared<> types, arrays of Shared<>, or object graphs which may contain a Shared<>.
            bool result =
                !IsSimpleValueType(type) &&
                type != typeof(string) &&
                ((type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Shared <>)) ||
                 (type.IsArray && IsClearRequired(type.GetElementType(), serializers)) ||
                 GetSerializableFields(type).Any(fi => IsClearRequired(fi.FieldType, serializers)));

            // cache the result
            handler.IsClearRequired = result;

            return(result);
        }
コード例 #3
0
        // **********************
        // the following methods do the heavy lifting of generating the IL code for each operation we support
        // **********************

        // emits code to clone all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitCloneFields(Type type, KnownSerializers serializers, ILGenerator il)
        {
            // simply invoke the type serializer for each relevant field
            foreach (FieldInfo field in GetClonableFields(type))
            {
                // argument legend: 0 = source, 1 = ref target, 2 = context
                if (IsSimpleValueType(field.FieldType) || field.FieldType == typeof(string))
                {
                    // for primitive types, simply copy the value from one field to the other
                    il.Emit(OpCodes.Ldarg_1); // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Stfld, field); // target.field
                }
                else
                {
                    // find the right serializer
                    var handler = serializers.GetUntypedHandler(field.FieldType);
                    int index   = serializers.GetIndex(handler);
                    il.Emit(OpCodes.Ldarg_2);                         // push context
                    il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                    il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                    // simply invoke the type serializer for each relevant field
                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Ldarg_1);      // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldflda, field); // target.field &
                    il.Emit(OpCodes.Ldarg_2);       // context

                    // handler.Clone(source.field, target.field, context);
                    var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Clone), BindingFlags.Public | BindingFlags.Instance);
                    il.Emit(OpCodes.Call, mi); // we have the right type, no need for callvirt
                }
            }

            il.Emit(OpCodes.Ret);
        }
コード例 #4
0
        // emits code to serialize all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitSerializeFields(Type type, KnownSerializers serializers, ILGenerator il, IEnumerable <MemberInfo> members = null)
        {
            // enumerate all fields and serialize each of them
            foreach (MemberInfo member in members ?? GetClonableFields(type))
            {
                // inner loop generates this code for each field or property:
                // var handler = GetHandlerFromIndex(index);
                // handler.Serialize(writer, source.fieldOrProp, context);

                // make sure the member is valid
                ValidateMember(type, member);

                // find the right serializer
                var mt      = (member.MemberType == MemberTypes.Field) ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
                var handler = serializers.GetUntypedHandler(mt);
                int index   = serializers.GetIndex(handler);
                il.Emit(OpCodes.Ldarg_2);                         // push context
                il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                // push the arguments
                il.Emit(OpCodes.Ldarg_0); // writer
                il.Emit(OpCodes.Ldarg_1); // source
                if (member.MemberType == MemberTypes.Field)
                {
                    il.Emit(OpCodes.Ldfld, (FieldInfo)member); // source.field
                }
                else
                {
                    var getter = ((PropertyInfo)member).GetGetMethod(true);
                    il.Emit(getter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, getter);
                }

                il.Emit(OpCodes.Ldarg_2); // context

                // call handler.Serialize(writer, source.field, context)
                var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Serialize), BindingFlags.Instance | BindingFlags.Public);
                il.Emit(OpCodes.Call, mi); // we have the right type, no need for callvirt
            }

            il.Emit(OpCodes.Ret);
        }
コード例 #5
0
        // emits code to deserialize all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitDeserializeFields(Type type, KnownSerializers serializers, ILGenerator il, IEnumerable <MemberInfo> members = null)
        {
            LocalBuilder localBuilder = null;

            // enumerate all fields and deserialize each of them
            foreach (MemberInfo member in members ?? GetClonableFields(type))
            {
                // inner loop generates this code for each field or property:
                // var handler = GetHandlerFromIndex(index);
                // handler.Deserialize(reader, ref target.fieldOrProp, context)

                // make sure the member is valid
                ValidateMember(type, member);

                // find the right serializer first
                var mt      = (member.MemberType == MemberTypes.Field) ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
                var handler = serializers.GetUntypedHandler(mt);
                int index   = serializers.GetIndex(handler);
                il.Emit(OpCodes.Ldarg_2);                         // push context
                il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                // argument legend: 0 = reader, 1 = ref target, 2 = context
                il.Emit(OpCodes.Ldarg_0); // reader
                il.Emit(OpCodes.Ldarg_1); // target&
                if (type.IsClass)
                {
                    il.Emit(OpCodes.Ldind_Ref);
                }

                if (member.MemberType == MemberTypes.Field)
                {
                    il.Emit(OpCodes.Ldflda, (FieldInfo)member); // target.field &
                }
                else
                {
                    var getter = ((PropertyInfo)member).GetGetMethod(true);
                    il.Emit(getter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, getter);
                    localBuilder = il.DeclareLocal(mt);
                    il.Emit(OpCodes.Stloc, localBuilder);
                    il.Emit(OpCodes.Ldloca, localBuilder);
                }

                il.Emit(OpCodes.Ldarg_2); // context

                // call handler.Deserialize(reader, ref target.field, context)
                var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Deserialize), BindingFlags.Instance | BindingFlags.Public);
                il.Emit(OpCodes.Call, mi); // not callvirt, since we have the right type

                // for properties, call the setter with the result
                if (member.MemberType == MemberTypes.Property)
                {
                    il.Emit(OpCodes.Ldarg_1); // target&
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldloc, localBuilder); // deserialization result
                    var setter = ((PropertyInfo)member).GetSetMethod(true);
                    il.Emit(setter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, setter);
                }
            }

            il.Emit(OpCodes.Ret);
        }
コード例 #6
0
ファイル: Generator.cs プロジェクト: yusharth/psi
        // **********************
        // the following methods do the heavy lifting of generating the IL code for each operation we support
        // **********************

        // emits code to clone all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitCloneFields(Type type, KnownSerializers serializers, ILGenerator il)
        {
            var cloningFlags = serializers.GetCloningFlags(type);

            // simply invoke the type serializer for each relevant field
            foreach (FieldInfo field in GetAllFields(type))
            {
                // fields with NonSerialized attribute should be skipped if SkipNonSerializedFields is set
                if (field.IsNotSerialized && cloningFlags.HasFlag(CloningFlags.SkipNonSerializedFields))
                {
                    continue;
                }

                // emit exceptions for other non-clonable fields
                else if ((field.FieldType == typeof(IntPtr) || field.FieldType == typeof(UIntPtr)) && !cloningFlags.HasFlag(CloningFlags.CloneIntPtrFields))
                {
                    EmitException(typeof(NotSupportedException), $"Cannot clone field:{field.Name} because cloning of {field.FieldType.Name} fields is disabled by default. To enable cloning of {field.FieldType.Name} fields for the containing type, register the type {type.AssemblyQualifiedName} with the {CloningFlags.CloneIntPtrFields} flag.", il);
                }
                else if (field.FieldType.IsPointer && !cloningFlags.HasFlag(CloningFlags.ClonePointerFields))
                {
                    EmitException(typeof(NotSupportedException), $"Cannot clone field:{field.Name} because cloning of pointer fields is disabled by default. To enable cloning of pointer fields for the containing type, register the type {type.AssemblyQualifiedName} with the {CloningFlags.ClonePointerFields} flag.", il);
                }

                // emit cloning code for clonable fields
                // argument legend: 0 = source, 1 = ref target, 2 = context
                else if (IsSimpleValueType(field.FieldType) || field.FieldType == typeof(string) || field.FieldType.IsPointer)
                {
                    // for primitive types, simply copy the value from one field to the other
                    il.Emit(OpCodes.Ldarg_1); // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Stfld, field); // target.field
                }
                else
                {
                    // find the right serializer
                    var handler = serializers.GetUntypedHandler(field.FieldType);
                    int index   = serializers.GetIndex(handler);
                    il.Emit(OpCodes.Ldarg_2);                         // push context
                    il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                    il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                    // simply invoke the type serializer for each relevant field
                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Ldarg_1);      // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldflda, field); // target.field &
                    il.Emit(OpCodes.Ldarg_2);       // context

                    // handler.Clone(source.field, target.field, context);
                    var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Clone), BindingFlags.Public | BindingFlags.Instance);
                    il.Emit(OpCodes.Call, mi); // we have the right type, no need for callvirt
                }
            }

            il.Emit(OpCodes.Ret);
        }