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());
        }