public void SearchAssemblyForUnionsOnTypes(IEnumerable <Tuple <Type, IEnumerable <Assembly> > > typesAndImplementationAssemblys) { foreach (var abstractOrInterfaceType in typesAndImplementationAssemblys) { TypeInfo ti = abstractOrInterfaceType.Item1.GetTypeInfo(); var allImplementations = abstractOrInterfaceType.Item2.SelectMany(s => { try { return(s.GetTypes()); } catch (Exception) { return(null); } }).Where(s => s != null && abstractOrInterfaceType.Item1.IsAssignableFrom(s)).ToList(); if (allImplementations.Count <= 0) { continue; } var implementationUnions = new Dictionary <Type, UnionAttribute>(); var count = 0; foreach (var implementation in allImplementations.Distinct()) { if (!implementationUnions.ContainsKey(implementation)) { var newUnion = new UnionAttribute(count, implementation); implementationUnions.Add(implementation, newUnion); count++; } } ExtraUnions.AddOrUpdate(abstractOrInterfaceType.Item1, implementationUnions.Values.ToArray(), (type, origUnions) => { var implementationUnions = new Dictionary <Type, UnionAttribute>(); var count = 0; foreach (var implementation in allImplementations.Union(origUnions.Select(s => s.SubType)).Distinct()) { if (!implementationUnions.ContainsKey(implementation)) { var newUnion = new UnionAttribute(count, implementation); implementationUnions.Add(implementation, newUnion); count++; } } return(implementationUnions.Values.ToArray()); }); } }
private static TypeInfo BuildType(Type type) { TypeInfo ti = type.GetTypeInfo(); // order by key(important for use jump-table of switch) UnionAttribute[] unionAttrsTemp = ti.GetCustomAttributes <UnionAttribute>().OrderBy(x => x.Key).ToArray(); ExtraUnions.TryGetValue(type, out var extraUnions); var unionAttrs = unionAttrsTemp; if (extraUnions?.Any() ?? false) { var allUnions = unionAttrsTemp.Union(extraUnions).ToList(); var implementationUnions = new Dictionary <Type, UnionAttribute>(); unionAttrs = new UnionAttribute[allUnions.Count]; var count = 0; foreach (var union in allUnions) { if (!implementationUnions.ContainsKey(union.SubType)) { var newUnion = new UnionAttribute(count, union.SubType); implementationUnions.Add(union.SubType, newUnion); count++; } } unionAttrs = implementationUnions.Values.ToArray(); } if (unionAttrs.Length == 0) { return(null); } if (!ti.IsInterface && !ti.IsAbstract) { throw new MessagePackDynamicUnionResolverException("Union can only be interface or abstract class. Type:" + type.Name); } var checker1 = new HashSet <int>(); var checker2 = new HashSet <Type>(); foreach (UnionAttribute item in unionAttrs) { if (!checker1.Add(item.Key)) { throw new MessagePackDynamicUnionResolverException("Same union key has found. Type:" + type.Name + " Key:" + item.Key); } if (!checker2.Add(item.SubType)) { throw new MessagePackDynamicUnionResolverException("Same union subType has found. Type:" + type.Name + " SubType: " + item.SubType); } } Type formatterType = typeof(IMessagePackFormatter <>).MakeGenericType(type); TypeBuilder typeBuilder = DynamicAssembly.DefineType("MessagePack.Formatters." + SubtractFullNameRegex.Replace(type.FullName, string.Empty).Replace(".", "_") + "Formatter" + +Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType }); FieldBuilder typeToKeyAndJumpMap = null; // Dictionary<RuntimeTypeHandle, KeyValuePair<int, int>> FieldBuilder keyToJumpMap = null; // Dictionary<int, int> // create map dictionary { ConstructorBuilder method = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); typeToKeyAndJumpMap = typeBuilder.DefineField("typeToKeyAndJumpMap", typeof(Dictionary <RuntimeTypeHandle, KeyValuePair <int, int> >), FieldAttributes.Private | FieldAttributes.InitOnly); keyToJumpMap = typeBuilder.DefineField("keyToJumpMap", typeof(Dictionary <int, int>), FieldAttributes.Private | FieldAttributes.InitOnly); ILGenerator il = method.GetILGenerator(); BuildConstructor(type, unionAttrs, method, typeToKeyAndJumpMap, keyToJumpMap, il); } { MethodBuilder method = typeBuilder.DefineMethod( "Serialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot, null, new Type[] { typeof(MessagePackWriter).MakeByRefType(), type, typeof(MessagePackSerializerOptions) }); ILGenerator il = method.GetILGenerator(); BuildSerialize(type, unionAttrs, method, typeToKeyAndJumpMap, il); } { MethodBuilder method = typeBuilder.DefineMethod( "Deserialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot, type, new Type[] { refMessagePackReader, typeof(MessagePackSerializerOptions) }); ILGenerator il = method.GetILGenerator(); BuildDeserialize(type, unionAttrs, method, keyToJumpMap, il); } return(typeBuilder.CreateTypeInfo()); }