如何将类型(按组)指向不同的 class and/or 命名空间?

How to point typings (by groups) to different class and/or namespace?

我能够为代码库中的所有 api 集生成类型,但是,我无法根据某些特征将它们分离到各种 类 and/or 名称空间中。作为示例业务需求,我想要基于类型的某些特征的三个不同的 类(and/or 命名空间),而不管它们来自何处。 Public(服务)、私有(服务)和内部(服务),但我想在运行时生成类型。这是我到目前为止所拥有的。我已经尝试覆盖 FunClassCodeGenerator() 中的 类。它有效,但会生成重复的 类 并且如某些阅读资料 AFAIK 所述,打字稿中没有部分 类。所有实验代码和评论都已删除。

// etc this is prepopulated.....
var newApiClasses = new List<Type>(); 
            builder.ExportAsClasses(newApiClasses, conf => conf
                .FlattenHierarchy()
                .Substitute(typeof(DateTime), new RtSimpleTypeName("Date"))
                .WithCodeGenerator<FunClassCodeGenerator>()
                .WithMethods(p => !p.GetCustomAttributes<AreaAttribute>().Any()  
                                  && !p.DeclaringType.GetCustomAttributes<AreaAttribute>().Any(),p => p.WithCodeGenerator<AngularActionCallGenerator>())
    
                .AddImport("{ Injectable }", "@angular/core")
                .AddImport("{ Observable }", "rxjs")
                .AddImport("{ Router }", "@angular/router")
                .Decorator(@"Injectable({
            providedIn: 'root'
})" + "\r\n")
                .DontIncludeToNamespace(true)
                .ExportTo(FileName($"{nameof(Routes)}.test")));
   public static class ServicesGenerator
    {
        public class FunClassCodeGenerator : ClassCodeGenerator
        {
            public override RtClass GenerateNode(Type element, RtClass result, TypeResolver resolver)
            {
                var r = base.GenerateNode(element, result, resolver);

                Console.WriteLine($"\n\n\n\n" +
                                  $"Information 102: {JsonConvert.SerializeObject(r.Name, Formatting.Indented)}" +
                                  $"\n\n\n\n");

                // constructor (router: Router) { }
                r.Members.Add(new RtConstructor()
                {
                    Order = 500,
                    Body = new RtRaw("this.router = router;"),
                    Arguments = new List<RtArgument>()
                    {
                        new RtArgument()
                        {
                            // not sure if this is private... private 
                            Identifier = new RtIdentifier("router"),
                            Type = new RtSimpleTypeName("Router")
                        }
                    },
                });

                // router: Router;
                r.Members.Add(new RtField()
                {
                    Order = -1,
                    Identifier = new RtIdentifier("router"),
                    Type = new RtSimpleTypeName("Router"),
                    LineAfter = "\r\n"
                });

                return r;
            }
        }

        public class AngularActionCallGenerator : MethodCodeGenerator
        {
            public override RtFunction GenerateNode(MethodInfo element, RtFunction result, TypeResolver resolver)
            {
                Console.Write($"104: {nameof(MethodCodeGenerator)} me first");

                if (IsNotWanted(element))
                    return null;

                Console.WriteLine($"Information 500: {JsonConvert.SerializeObject(result, Formatting.Indented)}");

                result = base.GenerateNode(element, result, resolver);
                if (result == null)
                    return null;
                result.Order = 1000;

                Console.WriteLine($"Information 501: {JsonConvert.SerializeObject(result, Formatting.Indented)}");

                result.IsStatic = false;

                var hasArea = element.GetCustomAttributes<AreaAttribute>().Any();
                var isHttpPost = element.GetCustomAttributes<HttpPostAttribute>().Any();
                var isHttpGet = !element.GetCustomAttributes<HttpPostAttribute>().Any();
                var isAuthOnly = !element.GetCustomAttributes<AllowAnonymousAttribute>().Any()
                                 && (element.GetCustomAttributes<AuthorizeAttribute>().Any()
                                     || element.DeclaringType?.GetCustomAttributes<AuthorizeAttribute>().Any() == true);

                // here we are overriding return type to corresponding promise
                var retType = result.ReturnType;
                var isVoid = retType is RtSimpleTypeName && ((RtSimpleTypeName)retType).TypeName == "void";

                // we use TypeResolver to get "any" type to avoid redundant type name construction
                // (or because I'm too lazy to manually construct "any" type)
                if (isVoid)
                    retType = resolver.ResolveTypeName(typeof(object));

                // Here we override TS method return type to make it angular.IPromise
                // We are using RtSimpleType with generic parameter of existing method type
                result.ReturnType = new RtSimpleTypeName(new[] { retType }, "", $"Promise");
                var flatReturnType = $"Promise<{retType}>";

                var p = element.GetParameters().Select(c => string.Format("'{0}': {0}", c.Name));

                var dataParameters = string.Join(", ", p);

                // Here we get path to controller
                // It is quite simple solution requiring /{controller}/{action} route
                var area = element.DeclaringType?.GetCustomAttributes<AreaAttribute>().FirstOrDefault()
                    ?.RouteValue;
                var controller = element.DeclaringType?.Name.Replace("Controller", string.Empty);
                var url = string.Join('/', new[] { "api", area, controller, element.Name }.Where(p2 => !string.IsNullOrWhiteSpace(p2)));

                var postOptions = $@", {{
    method: 'POST', {(dataParameters.Length > 0 ? $"\r\n\tbody: JSON.stringify({$"{{{dataParameters}}}"})," : string.Empty)}
    headers: {{
        'Content-Type': 'application/json'
    }}
}}";
                var getOptions = dataParameters.Length > 0
                    ? $@" + new URLSearchParams({{ {string.Join(", ", element.GetParameters().Select(c => string.Format("{0}: {0}.toString()", c.Name)))}}})"
                    : string.Empty;

                var fetch = $@"return fetch(`{url}{(getOptions.Length > 0 ? "?" : string.Empty)}`{(isHttpPost ? postOptions : getOptions)})
    .then(res => {{ var result = res.json(); console.log('this.router.url', this.router.url); console.log('result', res, result); if (res.redirected) {{ this.router.navigateByUrl(new URL(res.url).pathname) }} return result as {flatReturnType} }});";

                var code =
                    $"// IsHttpPost: {isHttpPost}" +
                    $"\r\n" +
                    $"// IsHttpGet: {isHttpGet}" +
                    $"\r\n" +
                    $"// IsAuthOnly: {isAuthOnly}" +
                    $"\r\n" +
                    $"{fetch}"
                    + (false
                        ? "\r\n" +
                          "// was: var params = {{ {dataParameters} }}; return this.http.post('{url}', params).then((response) => {{ response.data['requestParams'] = params; return response.data; }});"
                        : string.Empty);

                var body = new RtRaw(code);
                result.Body = body;
                result.LineAfter = "\r\n";

                return result;
            }
        }

        public static bool IsNotWanted(MethodInfo element)
        {
            if (element == null)
                return true;

            if (element.IsDefined(typeof(NonActionAttribute)))
                return true;

            if (element.IsFamily)
                return true;

            // element.GetBaseDefinition().DeclaringType == element.DeclaringType && , typeof(ControllerBase), typeof(Controller)
            if (new[] { typeof(IDisposable), typeof(IActionFilter), typeof(IAsyncActionFilter) }.Contains(element.ReflectedType))
                return true;

            if (element.IsPrivate)
                return true;

            if (element.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any()) // || element.IsOverride())
                return true;

            return false;
        }
    }

以下是对我自己的问题的粗略(但正确)回答。这些语句中的每一个都采用多种类型 (类) 及其方法,并根据标准轻松地将它们分开。请注意生成器仍将生成(空)类,无论它们是否具有任何符合条件的成员(方法)。这就是为什么我们在 types 的参数中使用 where 子句以及在第二组中使用 WithMethods(带参数)的原因代码。

builder.ExportAsClasses(types: allTypes.Where(p => p.IsSubclassOf(typeof(BaseAreaApiController)) 
                                                        && p.IsSubclassOf(typeof(BaseMembersAreaApiController))).ToList(), configuration: conf => conf
                .Substitute(typeof(DateTime), new RtSimpleTypeName("Date"))
                .WithCodeGenerator<FunClassCodeGenerator>()
                .WithPublicMethods(p => p.WithCodeGenerator<AngularActionCallGenerator>())
                .AddImport("{ Injectable }", "@angular/core")
                .AddImport("{ Observable }", "rxjs")
                .AddImport("{ Router }", "@angular/router")
                .Decorator("Injectable({ providedIn: 'root' })" + "\r\n")
                .OverrideNamespace("AreaServices")
                .ExportTo(FileName($"services.private")));

builder.ExportAsClasses(allTypes.Where(p => !p.IsSubclassOf(typeof(BaseAreaApiController))).ToList(), conf => conf
                .Substitute(typeof(DateTime), new RtSimpleTypeName("Date"))
                .WithCodeGenerator<FunClassCodeGenerator>()
                .WithMethods(p => !p.GetCustomAttributes<AuthorizeAttribute>().Any(), p2 => p2.WithCodeGenerator<AngularActionCallGenerator>())
                .AddImport("{ Injectable }", "@angular/core")
                .AddImport("{ Observable }", "rxjs")
                .AddImport("{ Router }", "@angular/router")
                .Decorator("Injectable({ providedIn: 'root' })" + "\r\n")
                .OverrideNamespace("PublicServices")
                .ExportTo(FileName($"services.public")));