news 2026/5/1 9:38:04

.Net如何自定义优雅实现代码生成器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.Net如何自定义优雅实现代码生成器

需求分析与场景定义

  • 明确代码生成器的目标:生成实体类、API控制器、DTO等常见场景
  • 典型应用场景:快速开发CRUD功能、减少重复编码工作
  • 核心需求:可配置性、模板灵活性、与项目结构无缝集成

具体实现可参考NetCoreKevin的kevin.CodeGenerator模块

基于.NET构建的企业级SaaS智能应用架构,采用前后端分离设计,具备以下核心特性:
前端技术:

  • Vue3前端框架
  • IDS4单点登录系统
  • 一库多租户解决方案
  • 多级缓存机制
  • CAP事件集成
  • SignalR实时通信
  • 领域驱动设计
  • AI智能体框架
  • RabbitMQ消息队列
  • 项目地址:github:https://github.com/junkai-li/NetCoreKevin
    Gitee: https://gitee.com/netkevin-li/NetCoreKevin

第一步:配置模板

模板配置示例如下图所示:

创建kevin.CodeGenerator模块

ICodeGeneratorService接口定义

usingkevin.CodeGenerator.Dto;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespacekevin.CodeGenerator{publicinterfaceICodeGeneratorService{/// <summary>/// 获取区域名称列表/// </summary>/// <returns></returns>Task<List<string>>GetAreaNames();/// <summary>/// 获取区域名称下面的表列表/// </summary>/// <returns></returns>Task<List<EntityItemDto>>GetAreaNameEntityItems(stringareaName);/// <summary>/// 生成代码/// </summary>/// <param name="entityItems"></param>/// <returns></returns>Task<bool>BulidCode(List<EntityItemDto>entityItems);}}

CodeGeneratorService实现

usingkevin.CodeGenerator.Dto;usingMicrosoft.CodeAnalysis;usingMicrosoft.CodeAnalysis.CSharp;usingMicrosoft.CodeAnalysis.CSharp.Syntax;usingMicrosoft.Extensions.Options;usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Reflection.Metadata;usingSystem.Text;usingstaticMicrosoft.CodeAnalysis.CSharp.SyntaxTokenParser;namespacekevin.CodeGenerator{publicclassCodeGeneratorService:ICodeGeneratorService{privateCodeGeneratorSetting_config;publicCodeGeneratorService(IOptionsMonitor<CodeGeneratorSetting>config){_config=config.CurrentValue;}publicasyncTask<List<string>>GetAreaNames(){return_config.CodeGeneratorItems.Select(t=>t.AreaName).ToList();}publicasyncTask<List<EntityItemDto>>GetAreaNameEntityItems(stringareaName){vararea=_config.CodeGeneratorItems.FirstOrDefault(t=>t.AreaName==areaName);if(area!=default){varentityItems=newList<EntityItemDto>();varpath="..\\..\\"+area.AreaPath.Trim().Replace(".","\\");// 遍历路径下的所有 .cs 文件if(!Directory.Exists(path)){thrownewArgumentException($"CodeGeneratorSetting配置:{areaName}{area.AreaPath}不存在");}else{varcsFiles=Directory.GetFiles(path,"*.cs",SearchOption.AllDirectories);foreach(varfileincsFiles){// 读取文件内容varcode=File.ReadAllText(file);vartree=CSharpSyntaxTree.ParseText(code);varroot=(CompilationUnitSyntax)tree.GetRoot();// 查找所有类声明varclassDeclarations=root.DescendantNodes().OfType<ClassDeclarationSyntax>();foreach(varclassDeclarationinclassDeclarations){// 检查类是否有 Table 特性if(classDeclaration.AttributeLists.Any(list=>list.Attributes.Any(attr=>attr.Name.ToString()=="Table"))){stringdescription="";// 检查类是否有 Description 特性vardescriptionAttr=classDeclaration.AttributeLists.SelectMany(list=>list.Attributes).FirstOrDefault(attr=>attr.Name.ToString()=="Description");if(descriptionAttr!=null){// 获取特性参数值vararg=descriptionAttr.ArgumentList?.Arguments.FirstOrDefault();if(arg?.ExpressionisLiteralExpressionSyntaxliteral){description=literal.Token.ValueText;}}entityItems.Add(newEntityItemDto{AreaName=area.AreaName,EntityName=classDeclaration.Identifier.Text,Description=$"{file}:{description}"});}}}returnentityItems;}}returnnewList<EntityItemDto>();}publicasyncTask<bool>BulidCode(List<EntityItemDto>entityItems){//获取对应的模板文件variRpTemplate=GetBuildCodeTemplate("IRp");varrpTemplate=GetBuildCodeTemplate("Rp");variServiceTemplate=GetBuildCodeTemplate("IService");varservice=GetBuildCodeTemplate("Service");foreach(variteminentityItems){vararea=_config.CodeGeneratorItems.FirstOrDefault(t=>t.AreaName==item.AreaName);if(area!=default){if(item.EntityName.StartsWith("T",StringComparison.OrdinalIgnoreCase)){item.EntityName=item.EntityName.Substring(1);}WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.IRpBulidPath}},iRpTemplate,$"../../{area.IRpBulidPath.Trim().Replace(".","\\")}/I{item.EntityName}Rp.cs");WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.RpBulidPath}},rpTemplate,$"../../{area.RpBulidPath.Trim().Replace(".","\\")}/{item.EntityName}Rp.cs");WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.IServiceBulidPath}},iServiceTemplate,$"../../{area.IServiceBulidPath.Trim().Replace(".","\\")}/I{item.EntityName}Service.cs");WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.ServiceBulidPath}},service,$"../../{area.ServiceBulidPath.Trim().Replace(".","\\")}/{item.EntityName}Service.cs");}}returntrue;}/// <summary>/// 获取对应模板文件/// </summary>/// <param name="name"></param>/// <returns></returns>privatestringGetBuildCodeTemplate(stringname){returnFile.ReadAllText("..\\..\\"+"Kevin\\kevin.Module\\kevin.CodeGenerator\\BuildCodeTemplate\\"+name+".txt",encoding:Encoding.UTF8);}/// <summary>/// 生成文件和代码/// </summary>/// <param name="paramters"></param>/// <param name="content"></param>/// <param name="savePath"></param>privatevoidWriteCode(Dictionary<string,string>paramters,stringcontent,stringsavePath){foreach(variteminparamters){content=content.Replace(item.Key,item.Value);}vardir=Path.GetDirectoryName(savePath);if(!Directory.Exists(dir)){Directory.CreateDirectory(dir);}if(File.Exists(savePath)){Console.WriteLine($"文件{savePath}已存在,跳过生成!");}else{File.WriteAllText(savePath,content,Encoding.UTF8);}}}}

CodeGeneratorSettingDto

namespacekevin.CodeGenerator.Dto{publicclassCodeGeneratorSetting{/// <summary>/// 配置文件相关信息/// </summary>publicList<CodeGeneratorItem>CodeGeneratorItems{get;set;}=new();}publicclassCodeGeneratorItem{/// <summary>/// 区域/// </summary>publicstringAreaName{get;set;}="";/// <summary>/// 数据库实体类路径/// </summary>publicstringAreaPath{get;set;}="";/// <summary>/// 仓储接口生成路径/// </summary>publicstringIRpBulidPath{get;set;}="";/// <summary>/// 仓储生成路径/// </summary>publicstringRpBulidPath{get;set;}="";/// <summary>/// 服务接口生成路径/// </summary>publicstringIServiceBulidPath{get;set;}="";/// <summary>/// 服务生成路径/// </summary>publicstringServiceBulidPath{get;set;}="";}}

配置Json文件

////代码生成器配置 .转换成/时要和路径一致 请配置好命名空间和路径对应关系"CodeGeneratorSetting":{"CodeGeneratorItems":[{"AreaName":"App.WebApi.v1",//项目命名"AreaPath":"App.Domain.Entities",//实体类路径"IRpBulidPath":"App.Domain.Interfaces.Repositorie.v1",//仓储接口命名空间和路径"RpBulidPath":"App.RepositorieRps.Repositories.v1",//仓储命名空间和路径"IServiceBulidPath":"App.Domain.Interfaces.Services.v1",//服务接口命名空间和路径"ServiceBulidPath":"App.Application.Services.v1"//服务命名空间和路径}]}

服务注入

services.AddKevinCodeGenerator(options=>{varsettings=Configuration.GetRequiredSection("CodeGeneratorSetting").Get<CodeGeneratorSetting>()!;options.CodeGeneratorItems=settings.CodeGeneratorItems;});

使用

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 6:15:30

OmenSuperHub:暗影精灵笔记本散热与性能管理终极指南

OmenSuperHub&#xff1a;暗影精灵笔记本散热与性能管理终极指南 【免费下载链接】OmenSuperHub 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 还在为官方控制软件的局限性而困扰吗&#xff1f;OmenSuperHub为您提供一套完整的离线解决方案&#xff0c;让…

作者头像 李华
网站建设 2026/5/1 6:15:30

大麦抢票助手实战攻略:从零开始的高效抢票指南

还在为抢不到热门演唱会门票而烦恼吗&#xff1f;大麦抢票助手正是您需要的智能抢票解决方案。这款基于Python开发的自动化工具能够智能模拟用户操作&#xff0c;大幅提升抢票成功率。本文将带您从基础配置到高级技巧&#xff0c;全面掌握这款抢票工具的使用方法。 【免费下载链…

作者头像 李华
网站建设 2026/5/1 6:15:27

Sketch文本替换效率革命:从手动修改到智能批处理的进阶指南

Sketch文本替换效率革命&#xff1a;从手动修改到智能批处理的进阶指南 【免费下载链接】Sketch-Find-And-Replace Sketch plugin to do a find and replace on text within layers 项目地址: https://gitcode.com/gh_mirrors/sk/Sketch-Find-And-Replace 你是否曾在深夜…

作者头像 李华
网站建设 2026/5/1 6:16:21

终极 macOS 鼠标滚动神器:Mos 让你的滚轮体验完美升级 [特殊字符]

终极 macOS 鼠标滚动神器&#xff1a;Mos 让你的滚轮体验完美升级 &#x1f680; 【免费下载链接】Mos 一个用于在 macOS 上平滑你的鼠标滚动效果或单独设置滚动方向的小工具, 让你的滚轮爽如触控板 | A lightweight tool used to smooth scrolling and set scroll direction i…

作者头像 李华
网站建设 2026/5/1 6:15:23

Windows PS3控制器蓝牙驱动:专业级兼容性解决方案

Windows PS3控制器蓝牙驱动&#xff1a;专业级兼容性解决方案 【免费下载链接】BthPS3 Windows kernel-mode Bluetooth Profile & Filter Drivers for PS3 peripherals 项目地址: https://gitcode.com/gh_mirrors/bt/BthPS3 技术背景与兼容性挑战 Windows操作系统原…

作者头像 李华
网站建设 2026/5/1 6:07:53

同或门行为级建模与FPGA下载流程详解

从一个同或门开始&#xff1a;手把手带你打通FPGA开发全流程你有没有过这样的经历&#xff1f;明明仿真波形完美无缺&#xff0c;结果一烧进FPGA&#xff0c;LED就是不亮&#xff1b;或者代码写得简洁优雅&#xff0c;综合报告却显示资源用了好几倍。这背后&#xff0c;往往不是…

作者头像 李华