Пример #1
0
        /// <summary>
        /// Ensure the following type can be serialized. If not, try to register appropriate serializer.
        /// This method can be recursive.
        /// </summary>
        /// <param name="type">The type.</param>
        public SerializableTypeInfo GenerateSerializer(TypeReference type, bool force = true, string profile = "Default", bool generic = false)
        {
            var serializableTypes = GetSerializableTypes(profile);

            // Already handled?
            SerializableTypeInfo serializableTypeInfo;

            if (serializableTypes.TryGetSerializableTypeInfo(type, generic, out serializableTypeInfo))
            {
                return(serializableTypeInfo);
            }

            // Try to get one without generic
            if (generic && serializableTypes.TryGetSerializableTypeInfo(type, false, out serializableTypeInfo))
            {
                return(serializableTypeInfo);
            }

            // TDOO: Array, List, Generic types, etc... (equivalent of previous serializer factories)
            var arrayType = type as ArrayType;

            if (arrayType != null)
            {
                // Only proceed if element type is serializable (and in Default profile, otherwise ElementType is enough)
                if (GenerateSerializer(arrayType.ElementType, force, profile) != null)
                {
                    if (profile == "Default")
                    {
                        var arraySerializerType = XenkoCoreModule.GetTypeResolved("Xenko.Core.Serialization.Serializers.ArraySerializer`1");
                        var serializerType      = new GenericInstanceType(arraySerializerType);
                        serializerType.GenericArguments.Add(arrayType.ElementType);
                        AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true), profile);
                        return(serializableTypeInfo);
                    }
                    else
                    {
                        // Fallback to default
                        return(GenerateSerializer(type, force, "Default"));
                    }
                }

                return(null);
            }

            // Try to match with existing generic serializer (for List, Dictionary, etc...)
            var genericInstanceType = type as GenericInstanceType;

            if (genericInstanceType != null)
            {
                var elementType = genericInstanceType.ElementType;
                SerializableTypeInfo elementSerializableTypeInfo;
                if ((elementSerializableTypeInfo = GenerateSerializer(elementType, false, profile, true)) != null)
                {
                    switch (elementSerializableTypeInfo.Mode)
                    {
                    case DataSerializerGenericMode.Type:
                    {
                        var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
                        serializerType.GenericArguments.Add(type);

                        AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true)
                            {
                                ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer
                            }, profile);
                        break;
                    }

                    case DataSerializerGenericMode.TypeAndGenericArguments:
                    {
                        var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
                        serializerType.GenericArguments.Add(type);
                        foreach (var genericArgument in genericInstanceType.GenericArguments)
                        {
                            // Generate serializer for each generic argument
                            //GenerateSerializer(genericArgument);

                            serializerType.GenericArguments.Add(genericArgument);
                        }

                        AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true)
                            {
                                ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer
                            }, profile);
                        break;
                    }

                    case DataSerializerGenericMode.GenericArguments:
                    {
                        var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
                        foreach (var genericArgument in genericInstanceType.GenericArguments)
                        {
                            // Generate serializer for each generic argument
                            //GenerateSerializer(genericArgument);

                            serializerType.GenericArguments.Add(genericArgument);
                        }

                        AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true)
                            {
                                ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer
                            }, profile);
                        break;
                    }

                    default:
                        throw new NotImplementedException();
                    }

                    if (elementSerializableTypeInfo.ComplexSerializer)
                    {
                        ProcessComplexSerializerMembers(type, serializableTypeInfo);
                    }
                    return(serializableTypeInfo);
                }
            }

            // Check complex type definitions
            if (profile == "Default" && (serializableTypeInfo = FindSerializerInfo(type, generic)) != null)
            {
                return(serializableTypeInfo);
            }

            // Fallback to default
            if (profile != "Default")
            {
                return(GenerateSerializer(type, force, "Default", generic));
            }

            // Part after that is only if a serializer is absolutely necessary. This is skipped when scanning normal assemblies type that might have nothing to do with serialization.
            if (!force)
            {
                return(null);
            }

            // Non instantiable type? (object, interfaces, abstract classes)
            // Serializer can be null since they will be inherited anyway (handled through MemberSerializer)
            var resolvedType = type.Resolve();

            if (resolvedType.IsAbstract || resolvedType.IsInterface || resolvedType.FullName == typeof(object).FullName)
            {
                AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(null, true), profile);
                return(serializableTypeInfo);
            }

            return(null);
        }
Пример #2
0
        /// <summary>
        /// Finds the serializer information.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="generic">If set to true, when using <see cref="DataSerializerGenericMode.Type"/>, it will returns the generic version instead of actual type one.</param>
        /// <returns></returns>
        /// <exception cref="System.InvalidOperationException">Not sure how to process this inherited serializer</exception>
        internal SerializableTypeInfo FindSerializerInfo(TypeReference type, bool generic)
        {
            if (type == null || type.FullName == typeof(object).FullName || type.FullName == typeof(ValueType).FullName || type.IsGenericParameter)
            {
                return(null);
            }

            var resolvedType = type.Resolve();

            // Nested type
            if (resolvedType.IsNested)
            {
                // Check public/private flags
                if (!resolvedType.IsNestedPublic && !resolvedType.IsNestedAssembly)
                {
                    return(null);
                }
            }

            if (resolvedType.IsEnum)
            {
                // Enum
                // Let's generate a EnumSerializer
                var enumSerializerType = XenkoCoreModule.GetTypeResolved("Xenko.Core.Serialization.Serializers.EnumSerializer`1");
                var serializerType     = new GenericInstanceType(enumSerializerType);
                serializerType.GenericArguments.Add(type);

                var serializableTypeInfo = new SerializableTypeInfo(serializerType, true, DataSerializerGenericMode.None);
                AddSerializableType(type, serializableTypeInfo);
                return(serializableTypeInfo);
            }

            // 1. Check if there is a Serializable attribute
            // Note: Not anymore since we don't want all system types to have unknown complex serializers.
            //if (((resolvedType.Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable) || resolvedType.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(SerializableAttribute).FullName))
            //{
            //    serializerInfo.Serializable = true;
            //    serializerInfo.ComplexSerializer = true;
            //    serializerInfo.ComplexSerializerName = SerializerTypeName(resolvedType);
            //    return serializerInfo;
            //}

            // 2.1. Check if there is DataSerializerAttribute on this type (if yes, it is serializable, but not a "complex type")
            var dataSerializerAttribute =
                resolvedType.CustomAttributes.FirstOrDefault(
                    x => x.AttributeType.FullName == "Xenko.Core.Serialization.DataSerializerAttribute");

            if (dataSerializerAttribute != null)
            {
                var modeField = dataSerializerAttribute.Fields.FirstOrDefault(x => x.Name == "Mode");
                var mode      = (modeField.Name != null) ? (DataSerializerGenericMode)modeField.Argument.Value : DataSerializerGenericMode.None;

                var dataSerializerType = ((TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value);

                // Reading from custom arguments doesn't have its ValueType properly set
                dataSerializerType = dataSerializerType.FixupValueType();

                if (mode == DataSerializerGenericMode.Type || (mode == DataSerializerGenericMode.TypeAndGenericArguments && type is GenericInstanceType))
                {
                    var genericSerializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode)
                    {
                        Inherited = true
                    };
                    AddSerializableType(type, genericSerializableTypeInfo);

                    var actualSerializerType = new GenericInstanceType(dataSerializerType);

                    // Add Type as generic arguments
                    actualSerializerType.GenericArguments.Add(type);

                    // If necessary, add generic arguments too
                    if (mode == DataSerializerGenericMode.TypeAndGenericArguments)
                    {
                        foreach (var genericArgument in ((GenericInstanceType)type).GenericArguments)
                        {
                            actualSerializerType.GenericArguments.Add(genericArgument);
                        }
                    }

                    // Special case for GenericMode == DataSerializerGenericMode.Type: we store actual serializer instantiation in SerializerType (alongside the generic version in GenericSerializerType).
                    var serializableTypeInfo = new SerializableTypeInfo(actualSerializerType, true);
                    AddSerializableType(type, serializableTypeInfo);

                    if (!generic)
                    {
                        return(serializableTypeInfo);
                    }

                    return(genericSerializableTypeInfo);
                }
                else
                {
                    var serializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode)
                    {
                        Inherited = false
                    };
                    AddSerializableType(type, serializableTypeInfo);
                    return(serializableTypeInfo);
                }
            }

            // 2.2. Check if SerializableExtendedAttribute is set on this class, or any of its base class with ApplyHierarchy
            var serializableExtendedAttribute =
                resolvedType.CustomAttributes.FirstOrDefault(
                    x => x.AttributeType.FullName == "Xenko.Core.DataContractAttribute");

            if (dataSerializerAttribute == null && serializableExtendedAttribute != null)
            {
                // CHeck if ApplyHierarchy is active, otherwise it needs to be the exact type.
                var inherited = serializableExtendedAttribute.Properties.Where(x => x.Name == "Inherited")
                                .Select(x => (bool)x.Argument.Value)
                                .FirstOrDefault();

                var serializableTypeInfo = CreateComplexSerializer(type);
                serializableTypeInfo.Inherited = inherited;

                // Process members
                ProcessComplexSerializerMembers(type, serializableTypeInfo);

                return(serializableTypeInfo);
            }

            // Check if parent type contains Inherited attribute
            var parentType = ResolveGenericsVisitor.Process(type, type.Resolve().BaseType);

            if (parentType != null)
            {
                // Generate serializer for parent type
                var parentSerializableInfoType = GenerateSerializer(parentType.Resolve(), false, generic: true);

                // If Inherited flag is on, we also generate a serializer for this type
                if (parentSerializableInfoType != null && parentSerializableInfoType.Inherited)
                {
                    if (parentSerializableInfoType.ComplexSerializer)
                    {
                        var serializableTypeInfo = CreateComplexSerializer(type);
                        serializableTypeInfo.Inherited = true;

                        // Process members
                        ProcessComplexSerializerMembers(type, serializableTypeInfo);

                        return(serializableTypeInfo);
                    }
                    else if (parentSerializableInfoType.Mode == DataSerializerGenericMode.Type || parentSerializableInfoType.Mode == DataSerializerGenericMode.TypeAndGenericArguments)
                    {
                        // Register generic version
                        var genericSerializableTypeInfo = new SerializableTypeInfo(parentSerializableInfoType.SerializerType, true, parentSerializableInfoType.Mode);
                        AddSerializableType(type, genericSerializableTypeInfo);

                        if (!type.HasGenericParameters)
                        {
                            var actualSerializerType = new GenericInstanceType(parentSerializableInfoType.SerializerType);

                            // Add Type as generic arguments
                            actualSerializerType.GenericArguments.Add(type);

                            // If necessary, add generic arguments too
                            if (parentSerializableInfoType.Mode == DataSerializerGenericMode.TypeAndGenericArguments)
                            {
                                foreach (var genericArgument in ((GenericInstanceType)parentType).GenericArguments)
                                {
                                    actualSerializerType.GenericArguments.Add(genericArgument);
                                }
                            }

                            // Register actual type
                            var serializableTypeInfo = new SerializableTypeInfo(actualSerializerType, true);
                            AddSerializableType(type, serializableTypeInfo);

                            if (!generic)
                            {
                                return(serializableTypeInfo);
                            }
                        }

                        return(genericSerializableTypeInfo);
                    }
                    else
                    {
                        throw new InvalidOperationException("Not sure how to process this inherited serializer");
                    }
                }
            }

            return(null);
        }