static void GenClassIdFuncs(Type baseClass, List <Type> typesToGenPolymorphMethods, SharpClassBuilder sink)
        {
            foreach (var type in typesToGenPolymorphMethods)
            {
                if (type.ReadGenCustomFlags() == type.ReadGenFlags())
                {
                    continue;
                }

                var tSink = GenClassSink(type);
                tSink.inheritance("IPolymorphable");
                if (type.IsAbstract)
                {
                    if (type == baseClass)
                    {
                        tSink.content(
                            $"public virtual {PolymorphClassIdType} {PolymorphClassIdFunc}(){{throw new NotImplementedException();}}");
                    }
                }
                else
                {
                    var mType         = type == baseClass ? MethodType.Virtual : MethodType.Override;
                    var classIdGetter = tSink.Method(PolymorphClassIdFunc, type, mType, PolymorphClassIdType, "");
                    classIdGetter.doNotCallBaseMethod = true;
                    if (type.IsGenericTypeDecl())
                    {
                        PrintGenericSwitch(type, classIdGetter,
                                           (t, s) => s.content(
                                               $"return ({PolymorphClassIdType}){TypeEnumName}.{t.UniqueName(false)};"));
                        classIdGetter.content("return 0;");
                    }
                    else
                    {
                        classIdGetter.content(
                            $"return ({PolymorphClassIdType}){TypeEnumName}.{type.UniqueName(false)};");
                    }
                }

                if (UseClassIdCaching)
                {
                    sink.content($"[GenIgnore] public {PolymorphClassIdTypeName} {PolymorphClassIdCached};");
                    var cachedGetter = sink.Method(PolymorphClassIdGetterName, baseClass, MethodType.Instance,
                                                   PolymorphClassIdType, "");
                    cachedGetter.content(
                        $"return {PolymorphClassIdCached} == 0 ? {PolymorphClassIdCached} = {PolymorphClassIdFunc}() : {PolymorphClassIdCached};");
                }
            }
        }
        static void GenPolymorphicRootSetup(Type baseClass, SharpClassBuilder sink,
                                            List <Type> typeIndexer, bool pooled)
        {
            string poolTypeArgIfAny = pooled ? $"{baseClass.PoolTypeName()} ," : "";

            if (pooled)
            {
                sink.usingSink("ZergRush.Alive");
            }

            // Array with constructors
            var constructorsArrayName = $"polymorph{(pooled ? "Pulled" : "")}Constructors";

            sink.content(
                $"static Func<{poolTypeArgIfAny}{baseClass.RealName()}> [] {constructorsArrayName} =" +
                $" new Func<{poolTypeArgIfAny}{baseClass.RealName()}> [] {{");
            sink.indent++;
            if (stubMode == false)
            {
                for (var i = 0; i < typeIndexer.Count; i++)
                {
                    var type = typeIndexer[i];
                    sink.content(
                        $"{(pooled ? "pool" : "()")} => {(type != null ? NewInstExpr(type, pooled) : "null")}, // {i}");
                }
            }

            sink.indent--;
            sink.content($"}};");

            // Create function
            sink.content(
                $"public static {baseClass.RealName()} {PolymorphInstanceFuncNamePooled(pooled)}(" +
                $"{PolymorphClassIdType} typeId{baseClass.OptPoolSecondArgDecl(pooled)}) {{");
            sink.content($"\treturn {constructorsArrayName}[typeId]({(pooled ? "pool" : "")});");
            sink.content($"}}");
        }