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 ComplexClassSerializerGenerator.GetSerializableItems(type, true)) { var resolvedType = serializableItem.Type.Resolve(); // Check that all closed types have a proper serializer if (serializableItem.Attributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.DataMemberCustomSerializerAttribute") || (resolvedType != null && resolvedType.IsInterface) || serializableItem.Type.ContainsGenericParameter()) { continue; } if (GenerateSerializer(serializableItem.Type, profile: profile) == null) { throw new InvalidOperationException(string.Format("Member {0} (type: {1}) doesn't seem to have a valid serializer.", serializableItem.MemberInfo, serializableItem.Type.ConvertCSharp())); } } }
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 ComplexClassSerializerGenerator.GetSerializableItems(type, true)) { var resolvedType = serializableItem.Type.Resolve(); // Check that all closed types have a proper serializer if (serializableItem.Attributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.DataMemberCustomSerializerAttribute") || (resolvedType != null && resolvedType.IsInterface) || serializableItem.Type.ContainsGenericParameter()) { continue; } if (GenerateSerializer(serializableItem.Type, profile: profile) == null) { ComplexClassSerializerGenerator.IgnoreMember(serializableItem.MemberInfo); log.Log(new LogMessage(log.Module, LogMessageType.Warning, string.Format("Member {0} does not have a valid serializer. Add [DataMemberIgnore], turn the member non-public, or add a [DataContract] to it's type.", serializableItem.MemberInfo))); } } }
private static void UpdateType(Type type, HashSet <Type> checkedTypes) { if (checkedTypes.Contains(type)) { return; } checkedTypes.Add(type); SerializableTypeInfo typeInfo = CheckSerializableTypeInfo(type); SerializableTypeCache[type] = typeInfo; if (typeInfo == null) { if (typeof(IList).IsAssignableFrom(type)) { Type elementType = GetListElementType(type); if (elementType != null) { UpdateType(elementType, checkedTypes); } return; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable <>)) { UpdateType(type.GetGenericArguments()[0], checkedTypes); return; } foreach (var info in type.GetFields()) { if (!info.IsStatic) { if (info.HasAttribute <Nullable>()) { NullableParamCache.Add(info); } UpdateType(info.FieldType, checkedTypes); } } foreach (var info in type.GetProperties()) { if (info.CanRead && info.CanWrite) { if (info.HasAttribute <Nullable>()) { NullableParamCache.Add(info); } UpdateType(info.PropertyType, checkedTypes); } } } }
void ISerializableTypeVisitor.VisitSerializableClass(SerializableTypeInfo serializableTypeInfo) { if (serializableTypeInfo.Type == null || serializableTypeInfo.Type.IsConcreteType()) { _serializers.Add(new DefaultSerializer(serializableTypeInfo)); _deserializers.Add(new DefaultDeserializer(serializableTypeInfo)); } }
public void AcceptOnType(ISerializableTypeVisitor visitor) { var typeInfo = new SerializableTypeInfo(Type, PackformatName, Version, SerializableMemberCandidates); if (HasDataContractAttribute) { CheckIfTypeHasProperDataContractAttirbuteInHierarchy(); visitor.VisitSerializableClass(typeInfo); } }
public void AddSerializableTypeInfo(TypeReference typeReference, SerializableTypeInfo serializableTypeInfo) { if (serializableTypeInfo.Mode != DataSerializerGenericMode.None) { GenericSerializableTypes.Add(typeReference, serializableTypeInfo); } else { SerializableTypes.Add(typeReference, serializableTypeInfo); } }
public void AddSerializableTypeInfo(TypeReference typeReference, SerializableTypeInfo serializableTypeInfo) { if (serializableTypeInfo.Mode != DataSerializerGenericMode.None) { GenericSerializableTypes.Add(typeReference, serializableTypeInfo); } else { if (IsFrozen) { throw new InvalidOperationException(string.Format("Unexpected type [{0}] to add while serializable types are frozen", typeReference)); } SerializableTypes.Add(typeReference, serializableTypeInfo); } }
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) { // Create a fake TypeReference (even though it doesn't really exist yet, but at least ConvertCSharp to get its name will work). var dataSerializerType = new TypeReference("SiliconStudio.DataSerializers", ComplexClassSerializerGenerator.SerializerTypeName(type, false, true), 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); } } var isLocal = type.Resolve().Module.Assembly == Assembly; 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); }
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); }
/// <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 = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.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; }
/// <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 = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.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); }
public bool TryGetSerializableTypeInfo(TypeReference type, bool generic, out SerializableTypeInfo result) { return(generic ? GenericSerializableTypes.TryGetValue(type, out result) : SerializableTypes.TryGetValue(type, out result)); }
/// <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 = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.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 == "SiliconStudio.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; // TODO: Replace with ResolveGenericsVisitor var dataSerializerType = ((TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value); 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 == "SiliconStudio.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; }
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 ComplexClassSerializerGenerator.GetSerializableItems(type, true)) { // Check that all closed types have a proper serializer if (serializableItem.Attributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.DataMemberCustomSerializerAttribute") || serializableItem.Type.ContainsGenericParameter()) continue; var resolvedType = serializableItem.Type.Resolve(); var isInterface = resolvedType != null && resolvedType.IsInterface; if (GenerateSerializer(serializableItem.Type, profile: profile) == null) { ComplexClassSerializerGenerator.IgnoreMember(serializableItem.MemberInfo); if (!isInterface) log.Log(new LogMessage(log.Module, LogMessageType.Warning, string.Format("Member {0} does not have a valid serializer. Add [DataMemberIgnore], turn the member non-public, or add a [DataContract] to it's type.", serializableItem.MemberInfo))); } } }
public DefaultDeserializer(SerializableTypeInfo serializableTypeInfo) : base(serializableTypeInfo.PackformatName, serializableTypeInfo.Version) { _serializableTypeInfo = serializableTypeInfo; _packItemCandidates = serializableTypeInfo.Items.ToDictionary(item => item.Name); }
public static void Serialize <T>(BinaryWriter writer, Type type, bool nullable, T value) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable <>)) { Type underlyingType = type.GetGenericArguments()[0]; Serialize(writer, underlyingType, true, value); return; } if (nullable) { if (value == null) { writer.Write((byte)0); return; } writer.Write((byte)1); } else if (value == null) { throw new SerializationException("Trying to serialize a non Nullable null value"); } Action <BinaryWriter, object, bool> serializerFunc; if (WriteFunctions.TryGetValue(type, out serializerFunc)) { serializerFunc(writer, value, nullable); return; } if (type.IsEnum) { Type underlyingType = Enum.GetUnderlyingType(type); if (WriteFunctions.TryGetValue(underlyingType, out serializerFunc)) { serializerFunc(writer, Convert.ChangeType(value, underlyingType), nullable); } else { throw new SerializationException("Enum " + type.Name + " underlying type is not serializable."); } return; } SerializableTypeInfo serTypeInfo = SerializableTypeCache[type]; if (serTypeInfo != null) { if (serTypeInfo.SerializeMethod.IsStatic) { serTypeInfo.SerializeMethod.Invoke(null, new object[] { value, writer }); } else { serTypeInfo.SerializeMethod.Invoke(value, new object[] { writer }); } return; } Type elementType = GetListElementType(type); if (elementType != null) { Action <BinaryWriter, object, bool> writeFunc = (wrtr, vlue, nlble) => { wrtr.Write(checked ((ushort)((ICollection)vlue).Count)); foreach (var el in (IEnumerable)vlue) { Serialize(wrtr, elementType, nlble, el); } }; WriteFunctions[type] = writeFunc; writeFunc(writer, value, nullable); return; } foreach (var info in RpcInterface.GetOrederedFields(type)) { if (!info.IsStatic) { Serialize(writer, info.FieldType, NullableParamCache.Contains(info), info.GetValue(value)); } } foreach (var info in RpcInterface.GetOrderedProperties(type)) { if (info.CanRead && info.CanWrite) { Serialize(writer, info.PropertyType, NullableParamCache.Contains(info), info.GetValue(value, null)); } } }
/// <summary> /// Finds the serializer information. /// </summary> /// <param name="type">The type.</param> /// <param name="isGenericType"> /// If set to <c>true</c>, when using <see cref="DataSerializerGenericMode.Type"/>, it will return the generic version /// instead of actual type one. /// </param> /// <returns>Serializer information for the specified type.</returns> /// <exception cref="InvalidOperationException">Not sure how to process this inherited serializer.</exception> internal SerializableTypeInfo FindSerializerInfo(TypeReference type, bool isGenericType) { if (type is 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 an EnumSerializer var enumSerializerType = StrideCoreModule.GetTypeResolved("Stride.Core.Serialization.Serializers.EnumSerializer`1"); var serializerType = new GenericInstanceType(enumSerializerType); serializerType.GenericArguments.Add(type); var serializableTypeInfo = new SerializableTypeInfo(serializerType, isLocal: true, DataSerializerGenericMode.None); AddSerializableType(type, serializableTypeInfo); return(serializableTypeInfo); } // 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 == "Stride.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, isLocal: true, mode) { IsInherited = 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, isLocal: true); AddSerializableType(type, serializableTypeInfo); if (!isGenericType) { return(serializableTypeInfo); } return(genericSerializableTypeInfo); } else { var serializableTypeInfo = new SerializableTypeInfo(dataSerializerType, isLocal: true, mode) { IsInherited = false }; AddSerializableType(type, serializableTypeInfo); return(serializableTypeInfo); } } // 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 == "Stride.Core.DataContractAttribute"); if (dataSerializerAttribute is 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.IsInherited = 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(), force: false, isGenericType: true); // If Inherited flag is on, we also generate a serializer for this type if (parentSerializableInfoType != null && parentSerializableInfoType.IsInherited) { if (parentSerializableInfoType.IsComplexSerializer) { var serializableTypeInfo = CreateComplexSerializer(type); serializableTypeInfo.IsInherited = true; // Process members ProcessComplexSerializerMembers(type, serializableTypeInfo); return(serializableTypeInfo); } else if (parentSerializableInfoType.GenericsMode == DataSerializerGenericMode.Type || parentSerializableInfoType.GenericsMode == DataSerializerGenericMode.TypeAndGenericArguments) { // Register generic version var genericSerializableTypeInfo = new SerializableTypeInfo(parentSerializableInfoType.SerializerType, isLocal: true, parentSerializableInfoType.GenericsMode); 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.GenericsMode == DataSerializerGenericMode.TypeAndGenericArguments) { foreach (var genericArgument in ((GenericInstanceType)parentType).GenericArguments) { actualSerializerType.GenericArguments.Add(genericArgument); } } // Register actual type var serializableTypeInfo = new SerializableTypeInfo(actualSerializerType, isLocal: true); AddSerializableType(type, serializableTypeInfo); if (!isGenericType) { return(serializableTypeInfo); } } return(genericSerializableTypeInfo); } else { throw new InvalidOperationException("Not sure how to process inherited serializer."); } } } return(null); }
public static object Deserialize(BinaryReader reader, Type type, bool nullable) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable <>)) { Type underlyingType = type.GetGenericArguments()[0]; return(Deserialize(reader, underlyingType, true)); } if (nullable && reader.ReadByte() == 0) { return(null); } Func <BinaryReader, bool, object> deserializerFunc; if (ReadFunctions.TryGetValue(type, out deserializerFunc)) { return(deserializerFunc(reader, nullable)); } if (type.IsEnum) { Type underlyingType = Enum.GetUnderlyingType(type); if (ReadFunctions.TryGetValue(underlyingType, out deserializerFunc)) { object value = deserializerFunc(reader, nullable); return(Enum.ToObject(type, value)); } throw new SerializationException("Enum " + type.Name + " underlying type is not serializable."); } SerializableTypeInfo serTypeInfo = SerializableTypeCache[type]; if (serTypeInfo != null) { if (serTypeInfo.DeserializeMethod != null) { return(serTypeInfo.DeserializeMethod.Invoke(null, new object[] { reader })); } if (serTypeInfo.Constructor != null) { return(Activator.CreateInstance(type, reader)); } } Type elementType = GetListElementType(type); if (elementType != null) { Func <BinaryReader, bool, object> readFunc; if (type.IsArray) { readFunc = (rdr, nlble) => { int length = rdr.ReadUInt16(); var array = (Array)Activator.CreateInstance(type, length); for (int i = 0; i < length; ++i) { array.SetValue(Deserialize(rdr, elementType, nlble), i); } return(array); }; } else { Type listType = typeof(List <>).MakeGenericType(elementType); readFunc = (rdr, nlble) => { int length = rdr.ReadUInt16(); var list = (IList)Activator.CreateInstance(listType); for (int i = 0; i < length; ++i) { list.Add(Deserialize(rdr, elementType, nlble)); } return(list); }; } ReadFunctions[type] = readFunc; return(readFunc(reader, nullable)); } var obj = Activator.CreateInstance(type); foreach (var info in RpcInterface.GetOrederedFields(type)) { if (!info.IsStatic) { var fieldValue = Deserialize(reader, info.FieldType, NullableParamCache.Contains(info)); info.SetValue(obj, fieldValue); } } foreach (var info in RpcInterface.GetOrderedProperties(type)) { if (info.CanRead && info.CanWrite) { var propValue = Deserialize(reader, info.PropertyType, NullableParamCache.Contains(info)); info.SetValue(obj, propValue, null); } } return(obj); }
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 ComplexClassSerializerGenerator.GetSerializableItems(type, true)) { var resolvedType = serializableItem.Type.Resolve(); // Check that all closed types have a proper serializer if (serializableItem.Attributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.DataMemberCustomSerializerAttribute") || (resolvedType != null && resolvedType.IsInterface) || serializableItem.Type.ContainsGenericParameter()) continue; if (GenerateSerializer(serializableItem.Type, profile: profile) == null) { throw new InvalidOperationException(string.Format("Member {0} (type: {1}) doesn't seem to have a valid serializer.", serializableItem.MemberInfo, serializableItem.Type.ConvertCSharp())); } } }
/// <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 = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.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 == "SiliconStudio.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; // TODO: Replace with ResolveGenericsVisitor var dataSerializerType = ((TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value); 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 == "SiliconStudio.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); }
private SerializableTypeInfo CreateComplexSerializer(TypeReference type) { // Create a fake TypeReference (even though it doesn't really exist yet, but at least ConvertCSharp to get its name will work). var dataSerializerType = new TypeReference("SiliconStudio.DataSerializers", ComplexClassSerializerGenerator.SerializerTypeName(type, false, true), 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); } } var isLocal = type.Resolve().Module.Assembly == Assembly; 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; }
public void AddSerializableType(TypeReference dataType, SerializableTypeInfo serializableTypeInfo, string profile = "Default") { SerializableTypeInfo currentValue; // Check if declaring type is generics var resolvedType = dataType.Resolve(); if (resolvedType != null && resolvedType.DeclaringType != null && (resolvedType.HasGenericParameters || resolvedType.DeclaringType.HasGenericParameters)) { throw new NotSupportedException(String.Format("Serialization of nested types referencing parent's generic parameters is not currently supported. " + "[Nested type={0} Parent={1}]", resolvedType.FullName, resolvedType.DeclaringType)); } var profileInfo = GetSerializableTypes(profile); if (profileInfo.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out currentValue)) { // TODO: Doesn't work in some generic case if (//currentValue.SerializerType.ConvertCSharp() != serializableTypeInfo.SerializerType.ConvertCSharp() || currentValue.Mode != serializableTypeInfo.Mode) { throw new InvalidOperationException(string.Format("Incompatible serializer found for same type in different assemblies for {0}", dataType.ConvertCSharp())); } return; } // Check that we don't simply try to add the same serializer than Default profile (optimized) SerializableTypeInfo defaultValue; if (profile != "Default" && SerializableTypes.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out defaultValue)) { if (defaultValue.SerializerType.FullName == serializableTypeInfo.SerializerType.FullName) { // Already added in default profile, early exit return; } } profileInfo.AddSerializableTypeInfo(dataType, serializableTypeInfo); // Scan and add dependencies (stored in EnumerateGenericInstantiations() functions). if (serializableTypeInfo.Local && serializableTypeInfo.SerializerType != null) { var resolvedSerializerType = serializableTypeInfo.SerializerType.Resolve(); if (resolvedSerializerType != null) { var enumerateGenericInstantiationsMethod = resolvedSerializerType.Methods.FirstOrDefault(x => x.Name == "EnumerateGenericInstantiations"); if (enumerateGenericInstantiationsMethod != null) { // Detect all ldtoken (attributes would have been better, but unfortunately C# doesn't allow generics in attributes) foreach (var inst in enumerateGenericInstantiationsMethod.Body.Instructions) { if (inst.OpCode.Code == Code.Ldtoken) { var type = (TypeReference)inst.Operand; // Try to "close" generics type with serializer type as a context var dependentType = ResolveGenericsVisitor.Process(serializableTypeInfo.SerializerType, type); if (!dependentType.ContainsGenericParameter()) { // Import type so that it becomes local to the assembly // (otherwise SerializableTypeInfo.Local will be false and it won't be instantiated) var importedType = Assembly.MainModule.ImportReference(dependentType); if (GenerateSerializer(importedType) == null) { throw new InvalidOperationException(string.Format("Could not find serializer for generic dependent type {0} when processing {1}", dependentType, dataType)); } } } } } } } }
public DefaultSerializer(SerializableTypeInfo serializableTypeInfo) : base(serializableTypeInfo.Type, serializableTypeInfo.PackformatName, serializableTypeInfo.Version) { _serializableTypeInfo = serializableTypeInfo; }
public bool TryGetSerializableTypeInfo(TypeReference type, bool generic, out SerializableTypeInfo result) { return generic ? GenericSerializableTypes.TryGetValue(type, out result) : SerializableTypes.TryGetValue(type, out result); }
public void AddSerializableTypeInfo(TypeReference typeReference, SerializableTypeInfo serializableTypeInfo) { if (serializableTypeInfo.Mode != DataSerializerGenericMode.None) GenericSerializableTypes.Add(typeReference, serializableTypeInfo); else { if (IsFrozen) { throw new InvalidOperationException(string.Format("Unexpected type [{0}] to add while serializable types are frozen", typeReference)); } SerializableTypes.Add(typeReference, serializableTypeInfo); } }
public void AddSerializableType(TypeReference dataType, SerializableTypeInfo serializableTypeInfo, string profile = "Default") { SerializableTypeInfo currentValue; // Check if declaring type is generics var resolvedType = dataType.Resolve(); if (resolvedType != null && resolvedType.DeclaringType != null && (resolvedType.HasGenericParameters || resolvedType.DeclaringType.HasGenericParameters)) throw new NotSupportedException(String.Format("Serialization of nested types referencing parent's generic parameters is not currently supported. " + "[Nested type={0} Parent={1}]", resolvedType.FullName, resolvedType.DeclaringType)); var profileInfo = GetSerializableTypes(profile); if (profileInfo.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out currentValue)) { // TODO: Doesn't work in some generic case if (//currentValue.SerializerType.ConvertCSharp() != serializableTypeInfo.SerializerType.ConvertCSharp() || currentValue.Mode != serializableTypeInfo.Mode) throw new InvalidOperationException(string.Format("Incompatible serializer found for same type in different assemblies for {0}", dataType.ConvertCSharp())); return; } // Check that we don't simply try to add the same serializer than Default profile (optimized) SerializableTypeInfo defaultValue; if (profile != "Default" && SerializableTypes.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out defaultValue)) { if (defaultValue.SerializerType.FullName == serializableTypeInfo.SerializerType.FullName) { // Already added in default profile, early exit return; } } profileInfo.AddSerializableTypeInfo(dataType, serializableTypeInfo); // Scan and add dependencies (stored in EnumerateGenericInstantiations() functions). if (serializableTypeInfo.Local && serializableTypeInfo.SerializerType != null) { var resolvedSerializerType = serializableTypeInfo.SerializerType.Resolve(); if (resolvedSerializerType != null) { var enumerateGenericInstantiationsMethod = resolvedSerializerType.Methods.FirstOrDefault(x => x.Name == "EnumerateGenericInstantiations"); if (enumerateGenericInstantiationsMethod != null) { // Detect all ldtoken (attributes would have been better, but unfortunately C# doesn't allow generics in attributes) foreach (var inst in enumerateGenericInstantiationsMethod.Body.Instructions) { if (inst.OpCode.Code == Code.Ldtoken) { var type = (TypeReference)inst.Operand; // Try to "close" generics type with serializer type as a context var dependentType = ResolveGenericsVisitor.Process(serializableTypeInfo.SerializerType, type); if (!dependentType.ContainsGenericParameter()) { // Import type so that it becomes local to the assembly // (otherwise SerializableTypeInfo.Local will be false and it won't be instantiated) var importedType = Assembly.MainModule.ImportReference(dependentType); if (GenerateSerializer(importedType) == null) { throw new InvalidOperationException(string.Format("Could not find serializer for generic dependent type {0} when processing {1}", dependentType, dataType)); } } } } } } } }
public bool TryGetSerializableTypeInfo(TypeReference type, bool isGeneric, out SerializableTypeInfo typeInfo) { return(isGeneric ? GenericSerializableTypes.TryGetValue(type, out typeInfo) : SerializableTypes.TryGetValue(type, out typeInfo)); }