public void ProcessSerializers(CecilSerializerContext context) { var defaultProfile = context.SerializableTypes; foreach (var profile in context.SerializableTypesProfiles) { // Skip default profile if (profile.Value == defaultProfile) { continue; } defaultProfile.IsFrozen = true; // For each profile, try to instantiate all types existing in default profile foreach (var type in defaultProfile.SerializableTypes) { context.GenerateSerializer(type.Key, false, profile.Key); } } }
public ComplexSerializerRegistry(PlatformType platform, AssemblyDefinition assembly, TextWriter log) { Assembly = assembly; ClassName = Utilities.BuildValidClassName(assembly.Name.Name) + "SerializerFactory"; // Register referenced assemblies serializer factory, so that we can call them recursively foreach (var referencedAssemblyName in assembly.MainModule.AssemblyReferences) { try { var referencedAssembly = assembly.MainModule.AssemblyResolver.Resolve(referencedAssemblyName); var assemblySerializerFactoryType = GetSerializerFactoryType(referencedAssembly); if (assemblySerializerFactoryType != null) { ReferencedAssemblySerializerFactoryTypes.Add(assemblySerializerFactoryType); } } catch (AssemblyResolutionException) { continue; } } // Find target framework and replicate it for serializer assembly. var targetFrameworkAttribute = assembly.CustomAttributes .FirstOrDefault(x => x.AttributeType.FullName == typeof(TargetFrameworkAttribute).FullName); if (targetFrameworkAttribute != null) { TargetFramework = "\"" + (string)targetFrameworkAttribute.ConstructorArguments[0].Value + "\""; var frameworkDisplayNameField = targetFrameworkAttribute.Properties.FirstOrDefault(x => x.Name == "FrameworkDisplayName"); if (frameworkDisplayNameField.Name != null) { TargetFramework += ", FrameworkDisplayName=\"" + (string)frameworkDisplayNameField.Argument.Value + "\""; } } // Prepare serializer processors Context = new CecilSerializerContext(platform, assembly, log); var processors = new List <ICecilSerializerProcessor>(); // Import list of serializer registered by referenced assemblies processors.Add(new ReferencedAssemblySerializerProcessor()); // Generate serializers for types tagged as serializable processors.Add(new CecilComplexClassSerializerProcessor()); // Generate serializers for PropertyKey and ParameterKey processors.Add(new PropertyKeySerializerProcessor()); // Update Engine (with AnimationData<T>) processors.Add(new UpdateEngineProcessor()); // Profile serializers processors.Add(new ProfileSerializerProcessor()); // Data contract aliases processors.Add(new DataContractAliasProcessor()); // Apply each processor foreach (var processor in processors) { processor.ProcessSerializers(Context); } }
public void ProcessSerializers(CecilSerializerContext context) { var references = new HashSet <AssemblyDefinition>(); EnumerateReferences(references, context.Assembly); var coreAssembly = CecilExtensions.FindCorlibAssembly(context.Assembly); // Only process assemblies depending on Xenko.Engine if (!references.Any(x => x.Name.Name == "SiliconStudio.Xenko.Engine")) { // Make sure Xenko.Engine.Serializers can access everything internally var internalsVisibleToAttribute = coreAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName); var serializationAssemblyName = "SiliconStudio.Xenko.Engine.Serializers"; // Add [InteralsVisibleTo] attribute var internalsVisibleToAttributeCtor = context.Assembly.MainModule.ImportReference(internalsVisibleToAttribute.GetConstructors().Single()); var internalsVisibleAttribute = new CustomAttribute(internalsVisibleToAttributeCtor) { ConstructorArguments = { new CustomAttributeArgument(context.Assembly.MainModule.ImportReference(context.Assembly.MainModule.TypeSystem.String), serializationAssemblyName) } }; context.Assembly.CustomAttributes.Add(internalsVisibleAttribute); return; } // Get or create method var updateEngineType = GetOrCreateUpdateType(context.Assembly, true); var mainPrepareMethod = new MethodDefinition("UpdateMain", MethodAttributes.HideBySig | MethodAttributes.Assembly | MethodAttributes.Static, context.Assembly.MainModule.TypeSystem.Void); updateEngineType.Methods.Add(mainPrepareMethod); // Get some useful Cecil objects from SiliconStudio.Core var siliconStudioCoreAssembly = context.Assembly.Name.Name == "SiliconStudio.Core" ? context.Assembly : context.Assembly.MainModule.AssemblyResolver.Resolve("SiliconStudio.Core"); var siliconStudioCoreModule = siliconStudioCoreAssembly.MainModule; var siliconStudioXenkoEngineAssembly = context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine" ? context.Assembly : context.Assembly.MainModule.AssemblyResolver.Resolve("SiliconStudio.Xenko.Engine"); var siliconStudioXenkoEngineModule = siliconStudioXenkoEngineAssembly.MainModule; // Generate IL for SiliconStudio.Core if (context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine") { ProcessXenkoEngineAssembly(context); } else { #if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG // We still process UpdatableProperty<T> since we had to revert it back when writing back Xenko.Engine (otherwise it crashes at AOT on iOS) new UpdatablePropertyCodeGenerator(siliconStudioXenkoEngineAssembly).GenerateUpdatablePropertyCode(); #endif } animationDataType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Animations.AnimationData`1"); var updatableFieldGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatableField`1"); updatableFieldGenericCtor = updatableFieldGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); updatablePropertyGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatableProperty`1"); updatablePropertyGenericCtor = updatablePropertyGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatablePropertyObjectGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatablePropertyObject`1"); updatablePropertyObjectGenericCtor = updatablePropertyObjectGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableListUpdateResolverGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.ListUpdateResolver`1"); updatableListUpdateResolverGenericCtor = updatableListUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableArrayUpdateResolverGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.ArrayUpdateResolver`1"); updatableArrayUpdateResolverGenericCtor = updatableArrayUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var registerMemberMethod = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMember"); var pclVisitor = new PclFixupTypeVisitor(coreAssembly); pclVisitor.VisitMethod(registerMemberMethod); updateEngineRegisterMemberMethod = context.Assembly.MainModule.ImportReference(registerMemberMethod); var registerMemberResolverMethod = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMemberResolver"); pclVisitor.VisitMethod(registerMemberResolverMethod); updateEngineRegisterMemberResolverMethod = context.Assembly.MainModule.ImportReference(registerMemberResolverMethod); var typeType = coreAssembly.MainModule.GetTypeResolved(typeof(Type).FullName); getTypeFromHandleMethod = context.Assembly.MainModule.ImportReference(typeType.Methods.First(x => x.Name == "GetTypeFromHandle")); // Make sure it is called at module startup var moduleInitializerAttribute = siliconStudioCoreModule.GetType("SiliconStudio.Core.ModuleInitializerAttribute"); var ctorMethod = moduleInitializerAttribute.GetConstructors().Single(x => !x.IsStatic && !x.HasParameters); pclVisitor.VisitMethod(ctorMethod); mainPrepareMethod.CustomAttributes.Add(new CustomAttribute(context.Assembly.MainModule.ImportReference(ctorMethod))); // Emit serialization code for all the types we care about var processedTypes = new HashSet <TypeDefinition>(TypeReferenceEqualityComparer.Default); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes)) { // Special case: when processing Xenko.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && siliconStudioXenkoEngineAssembly != context.Assembly) { continue; } var typeDefinition = serializableType.Key as TypeDefinition; if (typeDefinition == null) { continue; } // Ignore already processed types if (!processedTypes.Add(typeDefinition)) { continue; } try { ProcessType(context, typeDefinition, mainPrepareMethod); } catch (Exception e) { throw new InvalidOperationException(string.Format("Error when generating update engine code for {0}", typeDefinition), e); } } // Force generic instantiations var il = mainPrepareMethod.Body.GetILProcessor(); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes).ToArray()) { // Special case: when processing Xenko.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && siliconStudioXenkoEngineAssembly != context.Assembly) { continue; } // Make sure AnimationData<T> is serializable //if (serializableType.Value.Mode == DataSerializerGenericMode.None) // context.GenerateSerializer(context.Assembly.MainModule.ImportReference(animationDataType).MakeGenericType(context.Assembly.MainModule.ImportReference(serializableType.Key))); // Try to find if original method definition was generated var typeDefinition = serializableType.Key.Resolve(); // If using List<T>, register this type in UpdateEngine var listInterfaceType = typeDefinition.Interfaces.OfType <GenericInstanceType>().FirstOrDefault(x => x.ElementType.FullName == typeof(IList <>).FullName); if (listInterfaceType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ListUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, listInterfaceType.GenericArguments[0]); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableListUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType).FixupValueType())); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } // Same for arrays var arrayType = serializableType.Key as ArrayType; if (arrayType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ArrayUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, arrayType.ElementType); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableArrayUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType).FixupValueType())); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } var genericInstanceType = serializableType.Key as GenericInstanceType; if (genericInstanceType != null) { var expectedUpdateMethodName = ComputeUpdateMethodName(typeDefinition); var updateMethod = GetOrCreateUpdateType(typeDefinition.Module.Assembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); // If nothing was found in main assembly, also look in SiliconStudio.Xenko.Engine assembly, just in case (it might defines some shared/corlib types -- currently not the case) if (updateMethod == null) { updateMethod = GetOrCreateUpdateType(siliconStudioXenkoEngineAssembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); } if (updateMethod != null) { // Emit call to update engine setup method with generic arguments of current type il.Emit(OpCodes.Call, context.Assembly.MainModule.ImportReference(updateMethod) .MakeGenericMethod(genericInstanceType.GenericArguments .Select(context.Assembly.MainModule.ImportReference) .Select(CecilExtensions.FixupValueType).ToArray())); } } } il.Emit(OpCodes.Ret); #if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG // Due to Xamarin iOS AOT limitation, we can't keep this type around because it fails compilation if (context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine") { NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "GetStructAndUnbox")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "GetBlittable")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "SetStruct")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "SetBlittable")); } #endif }
public void ProcessType(CecilSerializerContext context, TypeReference type, MethodDefinition updateMainMethod) { var typeDefinition = type.Resolve(); // No need to process enum if (typeDefinition.IsEnum) { return; } var updateCurrentMethod = updateMainMethod; ResolveGenericsVisitor replaceGenericsVisitor = null; if (typeDefinition.HasGenericParameters) { // Make a prepare method for just this object since it might need multiple instantiation updateCurrentMethod = new MethodDefinition(ComputeUpdateMethodName(typeDefinition), MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static, context.Assembly.MainModule.TypeSystem.Void); var genericsMapping = new Dictionary <TypeReference, TypeReference>(); foreach (var genericParameter in typeDefinition.GenericParameters) { var genericParameterCopy = new GenericParameter(genericParameter.Name, updateCurrentMethod) { Attributes = genericParameter.Attributes, }; foreach (var constraint in genericParameter.Constraints) { genericParameterCopy.Constraints.Add(context.Assembly.MainModule.ImportReference(constraint)); } updateCurrentMethod.GenericParameters.Add(genericParameterCopy); genericsMapping[genericParameter] = genericParameterCopy; } replaceGenericsVisitor = new ResolveGenericsVisitor(genericsMapping); updateMainMethod.DeclaringType.Methods.Add(updateCurrentMethod); } var il = updateCurrentMethod.Body.GetILProcessor(); var emptyObjectField = updateMainMethod.DeclaringType.Fields.FirstOrDefault(x => x.Name == "emptyObject"); // Note: forcing fields and properties to be processed in all cases foreach (var serializableItem in ComplexClassSerializerGenerator.GetSerializableItems(type, true, ComplexTypeSerializerFlags.SerializePublicFields | ComplexTypeSerializerFlags.SerializePublicProperties | ComplexTypeSerializerFlags.Updatable)) { var fieldReference = serializableItem.MemberInfo as FieldReference; if (fieldReference != null) { var field = fieldReference.Resolve(); // First time it is needed, let's create empty object: var emptyObject = new object(); if (emptyObjectField == null) { emptyObjectField = new FieldDefinition("emptyObject", FieldAttributes.Static | FieldAttributes.Private, context.Assembly.MainModule.TypeSystem.Object); // Create static ctor that will initialize this object var staticConstructor = new MethodDefinition(".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, context.Assembly.MainModule.TypeSystem.Void); var staticConstructorIL = staticConstructor.Body.GetILProcessor(); staticConstructorIL.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(emptyObjectField.FieldType.Resolve().GetConstructors().Single(x => !x.IsStatic && !x.HasParameters))); staticConstructorIL.Emit(OpCodes.Stsfld, emptyObjectField); staticConstructorIL.Emit(OpCodes.Ret); updateMainMethod.DeclaringType.Fields.Add(emptyObjectField); updateMainMethod.DeclaringType.Methods.Add(staticConstructor); } il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, getTypeFromHandleMethod); il.Emit(OpCodes.Ldstr, field.Name); il.Emit(OpCodes.Ldsfld, emptyObjectField); il.Emit(OpCodes.Ldflda, context.Assembly.MainModule.ImportReference(fieldReference)); il.Emit(OpCodes.Conv_I); il.Emit(OpCodes.Ldsfld, emptyObjectField); il.Emit(OpCodes.Conv_I); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Conv_I4); var fieldType = context.Assembly.MainModule.ImportReference(replaceGenericsVisitor != null ? replaceGenericsVisitor.VisitDynamic(field.FieldType) : field.FieldType).FixupValueType(); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableFieldGenericCtor).MakeGeneric(fieldType)); il.Emit(OpCodes.Call, updateEngineRegisterMemberMethod); } var propertyReference = serializableItem.MemberInfo as PropertyReference; if (propertyReference != null) { var property = propertyReference.Resolve(); var propertyGetMethod = context.Assembly.MainModule.ImportReference(property.GetMethod).MakeGeneric(updateCurrentMethod.GenericParameters.ToArray()); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, getTypeFromHandleMethod); il.Emit(OpCodes.Ldstr, property.Name); il.Emit(OpCodes.Ldftn, propertyGetMethod); // Only get setter if it exists and it's public if (property.SetMethod != null && property.SetMethod.IsPublic) { var propertySetMethod = context.Assembly.MainModule.ImportReference(property.SetMethod).MakeGeneric(updateCurrentMethod.GenericParameters.ToArray()); il.Emit(OpCodes.Ldftn, propertySetMethod); } else { // 0 (native int) il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_I); } var propertyType = context.Assembly.MainModule.ImportReference(replaceGenericsVisitor != null ? replaceGenericsVisitor.VisitDynamic(property.PropertyType) : property.PropertyType).FixupValueType(); var updatablePropertyInflatedCtor = GetOrCreateUpdatablePropertyCtor(context.Assembly, propertyType); il.Emit(OpCodes.Newobj, updatablePropertyInflatedCtor); il.Emit(OpCodes.Call, updateEngineRegisterMemberMethod); } } if (updateCurrentMethod != updateMainMethod) { // If we have a local method, close it il.Emit(OpCodes.Ret); // Also call it from main method if it was a closed generic instantiation if (type is GenericInstanceType) { il = updateMainMethod.Body.GetILProcessor(); il.Emit(OpCodes.Call, updateCurrentMethod.MakeGeneric(((GenericInstanceType)type).GenericArguments.Select(context.Assembly.MainModule.ImportReference).Select(CecilExtensions.FixupValueType).ToArray())); } } }
public void ProcessSerializers(CecilSerializerContext context) { var references = new HashSet <AssemblyDefinition>(); EnumerateReferences(references, context.Assembly); var coreAssembly = CecilExtensions.FindCorlibAssembly(context.Assembly); // Only process assemblies depending on Stride.Engine if (!references.Any(x => x.Name.Name == "Stride.Engine")) { // Make sure Stride.Engine.Serializers can access everything internally var internalsVisibleToAttribute = coreAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName); var serializationAssemblyName = "Stride.Engine.Serializers"; // Add [InteralsVisibleTo] attribute var internalsVisibleToAttributeCtor = context.Assembly.MainModule.ImportReference(internalsVisibleToAttribute.GetConstructors().Single()); var internalsVisibleAttribute = new CustomAttribute(internalsVisibleToAttributeCtor) { ConstructorArguments = { new CustomAttributeArgument(context.Assembly.MainModule.ImportReference(context.Assembly.MainModule.TypeSystem.String), serializationAssemblyName) } }; context.Assembly.CustomAttributes.Add(internalsVisibleAttribute); return; } var strideEngineAssembly = context.Assembly.Name.Name == "Stride.Engine" ? context.Assembly : context.Assembly.MainModule.AssemblyResolver.Resolve(new AssemblyNameReference("Stride.Engine", null)); var strideEngineModule = strideEngineAssembly.MainModule; // Generate IL for Stride.Core if (context.Assembly.Name.Name == "Stride.Engine") { ProcessStrideEngineAssembly(context); } var updatableFieldGenericType = strideEngineModule.GetType("Stride.Updater.UpdatableField`1"); updatableFieldGenericCtor = updatableFieldGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); updatablePropertyGenericType = strideEngineModule.GetType("Stride.Updater.UpdatableProperty`1"); updatablePropertyGenericCtor = updatablePropertyGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatablePropertyObjectGenericType = strideEngineModule.GetType("Stride.Updater.UpdatablePropertyObject`1"); updatablePropertyObjectGenericCtor = updatablePropertyObjectGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableListUpdateResolverGenericType = strideEngineModule.GetType("Stride.Updater.ListUpdateResolver`1"); updatableListUpdateResolverGenericCtor = updatableListUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableArrayUpdateResolverGenericType = strideEngineModule.GetType("Stride.Updater.ArrayUpdateResolver`1"); updatableArrayUpdateResolverGenericCtor = updatableArrayUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var parameterCollectionResolver = strideEngineModule.GetType("Stride.Engine.Design.ParameterCollectionResolver"); parameterCollectionResolverInstantiateValueAccessor = parameterCollectionResolver.Methods.First(x => x.Name == "InstantiateValueAccessor"); var registerMemberMethod = strideEngineModule.GetType("Stride.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMember"); updateEngineRegisterMemberMethod = context.Assembly.MainModule.ImportReference(registerMemberMethod); var registerMemberResolverMethod = strideEngineModule.GetType("Stride.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMemberResolver"); //pclVisitor.VisitMethod(registerMemberResolverMethod); updateEngineRegisterMemberResolverMethod = context.Assembly.MainModule.ImportReference(registerMemberResolverMethod); var typeType = coreAssembly.MainModule.GetTypeResolved(typeof(Type).FullName); getTypeFromHandleMethod = context.Assembly.MainModule.ImportReference(typeType.Methods.First(x => x.Name == "GetTypeFromHandle")); var mainPrepareMethod = CreateUpdateMethod(context.Assembly); // Emit serialization code for all the types we care about var processedTypes = new HashSet <TypeDefinition>(TypeReferenceEqualityComparer.Default); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes)) { // Special case: when processing Stride.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && strideEngineAssembly != context.Assembly) { continue; } var typeDefinition = serializableType.Key as TypeDefinition; if (typeDefinition == null) { continue; } // Ignore already processed types if (!processedTypes.Add(typeDefinition)) { continue; } try { ProcessType(context, context.Assembly.MainModule.ImportReference(typeDefinition), mainPrepareMethod); } catch (Exception e) { throw new InvalidOperationException(string.Format("Error when generating update engine code for {0}", typeDefinition), e); } } // Force generic instantiations var il = mainPrepareMethod.Body.GetILProcessor(); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes).ToArray()) { // Special case: when processing Stride.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && strideEngineAssembly != context.Assembly) { continue; } // Try to find if original method definition was generated var typeDefinition = serializableType.Key.Resolve(); // If using List<T>, register this type in UpdateEngine var parentTypeDefinition = typeDefinition; while (parentTypeDefinition != null) { var listInterfaceType = parentTypeDefinition.Interfaces.Select(x => x.InterfaceType).OfType <GenericInstanceType>().FirstOrDefault(x => x.ElementType.FullName == typeof(IList <>).FullName); if (listInterfaceType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ListUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, listInterfaceType.GenericArguments[0]); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableListUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType))); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } parentTypeDefinition = parentTypeDefinition.BaseType?.Resolve(); } // Same for arrays var arrayType = serializableType.Key as ArrayType; if (arrayType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ArrayUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, arrayType.ElementType); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableArrayUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType))); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } // Generic instantiation for AOT platforms if (context.Platform == Core.PlatformType.iOS && serializableType.Key.Name == "ValueParameterKey`1") { var keyType = ((GenericInstanceType)serializableType.Key).GenericArguments[0]; il.Emit(OpCodes.Call, context.Assembly.MainModule.ImportReference(parameterCollectionResolverInstantiateValueAccessor).MakeGenericMethod(context.Assembly.MainModule.ImportReference(keyType))); } var genericInstanceType = serializableType.Key as GenericInstanceType; if (genericInstanceType != null) { var expectedUpdateMethodName = ComputeUpdateMethodName(typeDefinition); var updateMethod = GetOrCreateUpdateType(typeDefinition.Module.Assembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); // If nothing was found in main assembly, also look in Stride.Engine assembly, just in case (it might defines some shared/corlib types -- currently not the case) if (updateMethod == null) { updateMethod = GetOrCreateUpdateType(strideEngineAssembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); } if (updateMethod != null) { // Emit call to update engine setup method with generic arguments of current type il.Emit(OpCodes.Call, context.Assembly.MainModule.ImportReference(updateMethod) .MakeGenericMethod(genericInstanceType.GenericArguments .Select(context.Assembly.MainModule.ImportReference) .ToArray())); } } } il.Emit(OpCodes.Ret); }