static TypeDefinition GeneratePropertyBag(Context context, TypeReference containerType, TypeDefinition externalContainer, Dictionary <string, TypeDefinition> externalContainerTypes, MethodReference getTypeMethod, MethodReference createValueMethod, MethodReference createArrayMethod, MethodReference createListMethod, TypeReference unityObjectReference, TypeReference unityObjectListReference, TypeReference listType) { var effectiveContainerType = externalContainer ?? containerType; var propertyBagType = PropertyBag.GeneratePropertyBagHeader(context, effectiveContainerType, out var ctorMethod, out var addPropertyMethod); var il = ctorMethod.Body.GetILProcessor(); foreach (var(member, nameOverride) in CodeGenUtils.GetPropertyMembers(containerType.Resolve())) { if (CodeGenUtils.TryGenerateUnityObjectProperty(context, containerType, externalContainer, member, il, addPropertyMethod, createValueMethod, createArrayMethod, createListMethod, unityObjectReference, unityObjectListReference)) { continue; } var memberType = context.ImportReference(Utility.GetMemberType(member).ResolveGenericParameter(containerType)); TypeReference externalMember; if (memberType.IsArray) { externalContainerTypes.TryGetValue(memberType.GetElementType().FullName, out var externalMemberDefinition); externalMember = externalMemberDefinition?.MakeArrayType(); } else if (CodeGenUtils.IsListType(memberType, out var genericInstance)) { externalContainerTypes.TryGetValue(genericInstance.GenericArguments[0].FullName, out var externalMemberDefinition); externalMember = externalMemberDefinition == null ? null : listType.MakeGenericInstanceType(externalMemberDefinition); } else { externalContainerTypes.TryGetValue(memberType.FullName, out var externalMemberDefinition); externalMember = externalMemberDefinition; } var effectiveMemberType = externalMember ?? memberType; if (memberType.IsGenericInstance || memberType.IsArray) { PropertyBag.RegisterCollectionTypes(context, effectiveContainerType, effectiveMemberType, il); } TypeDefinition propertyType; if (externalMember != null || externalContainer != null) { propertyType = ReflectedExternalProperty.Generate(context, containerType, externalContainer, member, externalMember, getTypeMethod, nameOverride); } else if (member.IsPublicOrAssembly()) { propertyType = Property.Generate(context, containerType, member, nameOverride); } else { #if !NET_DOTS propertyType = ReflectedProperty.Generate(context, containerType, member, nameOverride); #else throw new Exception("Private properties require reflection which is not supported in NET_DOTS."); #endif } propertyBagType.NestedTypes.Add(propertyType); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Newobj, propertyType.GetConstructors().First()); il.Emit(OpCodes.Call, context.Module.ImportReference(addPropertyMethod.MakeGenericInstanceMethod(effectiveMemberType))); } il.Emit(OpCodes.Ret); return(propertyBagType); }
static TypeDefinition GeneratePropertyBag(Context context, TypeReference containerType, MethodReference createValueMethod, MethodReference createArrayMethod, MethodReference createListMethod, TypeReference unityObjectReference, TypeReference unityObjectListReference) { var propertyBagType = PropertyBag.GeneratePropertyBagHeader(context, containerType, out var ctorMethod, out var addPropertyMethod); var ctorMethodBody = ctorMethod.Body; var il = ctorMethodBody.GetILProcessor(); var baseCtorCall = ctorMethodBody.Instructions.Last(); foreach (var(member, nameOverride) in CodeGenUtils.GetPropertyMembers(containerType.Resolve())) { if (CodeGenUtils.TryGenerateUnityObjectProperty(context, containerType, null, member, il, addPropertyMethod, createValueMethod, createArrayMethod, createListMethod, unityObjectReference, unityObjectListReference)) { continue; } var memberType = context.ImportReference(Utility.GetMemberType(member).ResolveGenericParameter(containerType)); if (memberType.IsGenericInstance || memberType.IsArray) { PropertyBag.RegisterCollectionTypes(context, containerType, memberType, il); } TypeDefinition propertyType; // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (member.IsPublic()) { propertyType = Property.Generate(context, containerType, member, nameOverride); } else { #if !NET_DOTS propertyType = ReflectedProperty.Generate(context, containerType, member, nameOverride); #else throw new Exception("Private properties require reflection which is not supported in NET_DOTS."); #endif } propertyBagType.NestedTypes.Add(propertyType); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Newobj, propertyType.GetConstructors().First()); il.Emit(OpCodes.Call, context.Module.ImportReference(addPropertyMethod.MakeGenericInstanceMethod(memberType))); } il.Emit(OpCodes.Ret); var nop = il.Create(OpCodes.Nop); var ret = il.Create(OpCodes.Ret); var leave = il.Create(OpCodes.Leave, ret); il.InsertAfter(ctorMethodBody.Instructions.Last(), nop); il.InsertAfter(nop, leave); il.InsertAfter(leave, ret); var handler = new ExceptionHandler(ExceptionHandlerType.Catch) { TryStart = baseCtorCall.Next, TryEnd = nop, HandlerStart = nop, HandlerEnd = ret, CatchType = context.Module.ImportReference(typeof(Exception)) }; ctorMethodBody.ExceptionHandlers.Add(handler); return(propertyBagType); }
static void PostProcessType(TypeDefinition type, HashSet <TypeDefinition> serializableTypes) { if (type.HasGenericParameters && !type.IsGenericInstance) { return; } foreach (var(member, _) in CodeGenUtils.GetPropertyMembers(type)) { var memberType = Utility.GetMemberType(member).ResolveGenericParameter(type); var resolvedMemberType = memberType.Resolve(); if (resolvedMemberType == null) { Console.Error.WriteLine($"Couldn't resolve {memberType}"); continue; } if (memberType.IsArray) { resolvedMemberType = resolvedMemberType.GetElementType().Resolve(); } else if (CodeGenUtils.IsListType(memberType, out var genericInstance)) { resolvedMemberType = genericInstance.GenericArguments[0].Resolve(); } else { resolvedMemberType = resolvedMemberType.Resolve(); } if (resolvedMemberType.HasGenericParameters && !resolvedMemberType.IsGenericInstance) { continue; } var(hasSkipGenerationAttribute, hasCompilerGeneratedAttribute) = CodeGenUtils.GetSerializationAttributes(resolvedMemberType); if (hasSkipGenerationAttribute || hasCompilerGeneratedAttribute) { continue; } // Skip UnityObjectTypes because we will be using UnityObjectReferenceProperty if (CodeGenUtils.IsAssignableToUnityObject(resolvedMemberType)) { continue; } if (!CodeGenUtils.IsSerializableContainer(resolvedMemberType)) { if (!resolvedMemberType.IsValueType || CodeGenUtils.TypeIsPrimitive(resolvedMemberType, resolvedMemberType.FullName)) { continue; } } if (serializableTypes.Add(resolvedMemberType)) { PostProcessType(resolvedMemberType, serializableTypes); } } }