news 2026/3/6 13:26:11

.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/2/25 15:13:27

柔性电路板上LED布局的工程实践指南

柔性电路板上LED布局的实战工程笔记&#xff1a;从失效案例到高可靠设计最近在做一款可穿戴设备的侧边氛围灯项目&#xff0c;客户要求“超薄、贴合弧形外壳、支持动态呼吸光效”&#xff0c;听起来很酷。但当我拿到FPC布线图时&#xff0c;眉头一皱——三颗0603 LED一字排开&a…

作者头像 李华
网站建设 2026/3/6 0:39:44

Midscene.js企业级实战指南:从零搭建高效自动化部署体系

Midscene.js企业级实战指南&#xff1a;从零搭建高效自动化部署体系 【免费下载链接】midscene Let AI be your browser operator. 项目地址: https://gitcode.com/GitHub_Trending/mid/midscene 在当今快节奏的数字化时代&#xff0c;企业级自动化部署已成为提升研发效…

作者头像 李华
网站建设 2026/2/27 9:39:34

5分钟解锁PPTist:从设计小白到专业演示高手的进阶指南

5分钟解锁PPTist&#xff1a;从设计小白到专业演示高手的进阶指南 【免费下载链接】PPTist 基于 Vue3.x TypeScript 的在线演示文稿&#xff08;幻灯片&#xff09;应用&#xff0c;还原了大部分 Office PowerPoint 常用功能&#xff0c;实现在线PPT的编辑、演示。支持导出PPT…

作者头像 李华
网站建设 2026/3/1 1:35:47

anything-llm能否支持MQTT?物联网消息协议集成设想

anything-llm能否支持MQTT&#xff1f;物联网消息协议集成设想 在智能制造车间的某个角落&#xff0c;一台老旧电机突然发出过热警报。现场工人还没来得及翻找纸质手册&#xff0c;他的移动终端已经弹出一条结构化建议&#xff1a;“E102错误码&#xff1a;请立即检查冷却风扇…

作者头像 李华
网站建设 2026/3/4 0:53:14

桌面Overleaf离线LaTeX编辑工具:让学术写作告别网络依赖

桌面Overleaf离线LaTeX编辑工具&#xff1a;让学术写作告别网络依赖 【免费下载链接】NativeOverleaf Next-level academia! Repository for the Native Overleaf project, attempting to integrate Overleaf with native OS features for macOS, Linux and Windows. 项目地址…

作者头像 李华
网站建设 2026/3/3 21:41:25

macOS鼠标优化终极方案:告别卡顿,让滚轮如丝般顺滑

你是否曾经为macOS上鼠标滚动的生硬感而烦恼&#xff1f;外接鼠标在苹果系统上的表现总是不尽人意&#xff0c;滚动卡顿、方向混乱等问题严重影响了工作效率。今天我要介绍的Mos工具&#xff0c;就是专门为解决这一痛点而生的完美解决方案。这款轻量级工具能够平滑你的鼠标滚动…

作者头像 李华