public MethodReference GetOrCreateUpdatablePropertyCtor(AssemblyDefinition assembly, TypeReference propertyType) { if (propertyType.Resolve().IsValueType) { #if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG // Temporary code until Xamarin fixes bugs with generics calli // For now, we simply create one class per type T instead of using UpdatableProperty<T> // Later, we should only use UpdatableProperty<T> for everything var updateEngineType = GetOrCreateUpdateType(assembly, true); var updatablePropertyInflatedTypeName = $"UpdatableProperty_{propertyType.ConvertCSharp().Replace('.', '_').Replace("[]", "Array")}"; var updatablePropertyInflatedType = updateEngineType.NestedTypes.FirstOrDefault(x => x.Name == updatablePropertyInflatedTypeName); if (updatablePropertyInflatedType == null) { var genericMapping = new Dictionary<TypeReference, TypeReference>(); genericMapping.Add(updatablePropertyGenericType.GenericParameters[0], propertyType); updatablePropertyInflatedType = new TypeDefinition(string.Empty, updatablePropertyInflatedTypeName, TypeAttributes.NestedPrivate | TypeAttributes.AutoClass | TypeAttributes.AnsiClass); updateEngineType.NestedTypes.Add(updatablePropertyInflatedType); CecilExtensions.InflateGenericType(updatablePropertyGenericType, updatablePropertyInflatedType, propertyType); } var updatablePropertyCtor = updatablePropertyInflatedType.Methods.First(x => x.IsConstructor && !x.IsStatic); return assembly.MainModule.ImportReference(updatablePropertyCtor); #else return assembly.MainModule.ImportReference(updatablePropertyGenericCtor).MakeGeneric(propertyType); #endif } else { return assembly.MainModule.ImportReference(updatablePropertyObjectGenericCtor).MakeGeneric(propertyType); } }
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)); } } } } } } } }