public void ProcessSerializers(CecilSerializerContext context) { // Iterate over each static member of type PropertyKey<> or ParameterKey<> foreach (var type in context.Assembly.MainModule.GetAllTypes()) { foreach (var member in type.Fields) { if (!member.IsStatic || !member.IsPublic) { continue; } if (ComplexSerializerRegistry.IsMemberIgnored(member.CustomAttributes, ComplexTypeSerializerFlags.SerializePublicFields, DataMemberMode.Default)) { continue; } if (member.FieldType.Name == "PropertyKey`1" || member.FieldType.Name == "ParameterKey`1" || member.FieldType.Name == "ValueParameterKey`1" || member.FieldType.Name == "ObjectParameterKey`1" || member.FieldType.Name == "PermutationParameterKey`1") { context.GenerateSerializer(member.FieldType); var genericType = (GenericInstanceType)member.FieldType; // Also generate serializer for embedded type context.GenerateSerializer(genericType.GenericArguments[0]); } } } }
private void ProcessComplexSerializerMembers(TypeReference type, SerializableTypeInfo serializableTypeInfo, string profile = "Default") { // Process base type (for complex serializers) // If it's a closed type and there is a serializer, we'll serialize parent SerializableTypeInfo parentSerializableTypeInfo; var parentType = ResolveGenericsVisitor.Process(type, type.Resolve().BaseType); if (!parentType.ContainsGenericParameter() && (parentSerializableTypeInfo = GenerateSerializer(parentType, false, profile)) != null && parentSerializableTypeInfo.SerializerType != null) { serializableTypeInfo.ComplexSerializerProcessParentType = true; } // Process members foreach (var serializableItem in ComplexSerializerRegistry.GetSerializableItems(type, true)) { // Check that all closed types have a proper serializer if (serializableItem.Attributes.Any(x => x.AttributeType.FullName == "Xenko.Core.DataMemberCustomSerializerAttribute") || serializableItem.Type.ContainsGenericParameter()) { continue; } var resolvedType = serializableItem.Type.Resolve(); var isInterface = resolvedType != null && resolvedType.IsInterface; try { if (GenerateSerializer(serializableItem.Type, profile: profile) == null) { ComplexSerializerRegistry.IgnoreMember(serializableItem.MemberInfo); if (!isInterface) { log.Write( $"Warning: Member {serializableItem.MemberInfo} does not have a valid serializer. Add [DataMemberIgnore], turn the member non-public, or add a [DataContract] to it's type."); } } } catch (Exception e) { throw new InvalidOperationException($"Could not process serialization for member {serializableItem.MemberInfo}", e); } } }
private SerializableTypeInfo CreateComplexSerializer(TypeReference type) { var isLocal = type.Resolve().Module.Assembly == Assembly; // Create a fake TypeReference (even though it doesn't really exist yet, but at least ConvertCSharp to get its name will work). TypeReference dataSerializerType; var className = ComplexSerializerRegistry.SerializerTypeName(type, false, true); if (type.HasGenericParameters) { className += "`" + type.GenericParameters.Count; } if (isLocal && type is TypeDefinition) { dataSerializerType = new TypeDefinition("Xenko.Core.DataSerializers", className, TypeAttributes.AnsiClass | TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit | (type.HasGenericParameters ? TypeAttributes.Public : TypeAttributes.NotPublic)); // TODO: Only if not using Roslyn Assembly.MainModule.Types.Add((TypeDefinition)dataSerializerType); } else { dataSerializerType = new TypeReference("Xenko.Core.DataSerializers", className, type.Module, type.Scope); } var mode = DataSerializerGenericMode.None; if (type.HasGenericParameters) { mode = DataSerializerGenericMode.GenericArguments; // Clone generic parameters foreach (var genericParameter in type.GenericParameters) { var newGenericParameter = new GenericParameter(genericParameter.Name, dataSerializerType) { Attributes = genericParameter.Attributes }; // Clone type constraints (others will be in Attributes) foreach (var constraint in genericParameter.Constraints) { newGenericParameter.Constraints.Add(constraint); } dataSerializerType.GenericParameters.Add(newGenericParameter); } } if (dataSerializerType is TypeDefinition dataSerializerTypeDefinition) { // Setup base class var resolvedType = type.Resolve(); var useClassDataSerializer = resolvedType.IsClass && !resolvedType.IsValueType && !resolvedType.IsAbstract && !resolvedType.IsInterface && resolvedType.GetEmptyConstructor() != null; var classDataSerializerType = Assembly.GetXenkoCoreModule().GetType(useClassDataSerializer ? "Xenko.Core.Serialization.ClassDataSerializer`1" : "Xenko.Core.Serialization.DataSerializer`1"); var parentType = Assembly.MainModule.ImportReference(classDataSerializerType).MakeGenericType(type.MakeGenericType(dataSerializerType.GenericParameters.ToArray <TypeReference>())); //parentType = ResolveGenericsVisitor.Process(serializerType, type.BaseType); dataSerializerTypeDefinition.BaseType = parentType; } var serializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode); serializableTypeInfo.Local = type.Resolve().Module.Assembly == Assembly; AddSerializableType(type, serializableTypeInfo); if (isLocal && type is TypeDefinition) { ComplexTypes.Add((TypeDefinition)type, serializableTypeInfo); } serializableTypeInfo.ComplexSerializer = true; return(serializableTypeInfo); }