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接口定义
using kevin.CodeGenerator.Dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace kevin.CodeGenerator
{
public interface ICodeGeneratorService
{
/// <summary>
/// 获取区域名称列表
/// </summary>
/// <returns></returns>
Task<List<string>> GetAreaNames();
/// <summary>
/// 获取区域名称下面的表列表
/// </summary>
/// <returns></returns>
Task<List<EntityItemDto>> GetAreaNameEntityItems(string areaName);
/// <summary>
/// 生成代码
/// </summary>
/// <param name="entityItems"></param>
/// <returns></returns>
Task<bool> BulidCode(List<EntityItemDto> entityItems);
}
}
CodeGeneratorService实现
using kevin.CodeGenerator.Dto;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser;
namespace kevin.CodeGenerator
{
public class CodeGeneratorService : ICodeGeneratorService
{
private CodeGeneratorSetting _config;
public CodeGeneratorService(IOptionsMonitor<CodeGeneratorSetting> config)
{
_config = config.CurrentValue;
}
public async Task<List<string>> GetAreaNames()
{
return _config.CodeGeneratorItems.Select(t => t.AreaName).ToList();
}
public async Task<List<EntityItemDto>> GetAreaNameEntityItems(string areaName)
{
var area = _config.CodeGeneratorItems.FirstOrDefault(t => t.AreaName == areaName);
if (area != default)
{
var entityItems = new List<EntityItemDto>();
var path = "..\\..\\" + area.AreaPath.Trim().Replace(".", "\\");
// 遍历路径下的所有 .cs 文件
if (!Directory.Exists(path))
{
throw new ArgumentException($"CodeGeneratorSetting配置:{areaName}{area.AreaPath}不存在");
}
else
{
var csFiles = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories);
foreach (var file in csFiles)
{
// 读取文件内容
var code = File.ReadAllText(file);
var tree = CSharpSyntaxTree.ParseText(code);
var root = (CompilationUnitSyntax)tree.GetRoot();
// 查找所有类声明
var classDeclarations = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach (var classDeclaration in classDeclarations)
{
// 检查类是否有 Table 特性
if (classDeclaration.AttributeLists.Any(list =>
list.Attributes.Any(attr =>
attr.Name.ToString() == "Table")))
{
string description = "";
// 检查类是否有 Description 特性
var descriptionAttr = classDeclaration.AttributeLists
.SelectMany(list => list.Attributes)
.FirstOrDefault(attr => attr.Name.ToString() == "Description");
if (descriptionAttr != null)
{
// 获取特性参数值
var arg = descriptionAttr.ArgumentList?.Arguments.FirstOrDefault();
if (arg?.Expression is LiteralExpressionSyntax literal)
{
description = literal.Token.ValueText;
}
}
entityItems.Add(new EntityItemDto
{
AreaName = area.AreaName,
EntityName = classDeclaration.Identifier.Text,
Description = $"{file}: {description}"
});
}
}
}
return entityItems;
}
}
return new List<EntityItemDto>();
}
public async Task<bool> BulidCode(List<EntityItemDto> entityItems)
{
//获取对应的模板文件
var iRpTemplate = GetBuildCodeTemplate("IRp");
var rpTemplate = GetBuildCodeTemplate("Rp");
var iServiceTemplate = GetBuildCodeTemplate("IService");
var service = GetBuildCodeTemplate("Service");
foreach (var item in entityItems)
{
var area = _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(new Dictionary<string, string>
{
{ "%entityName%",item.EntityName},
{ "%namespacePath%",area.IRpBulidPath}
}, iRpTemplate, $"../../{area.IRpBulidPath.Trim().Replace(".", "\\")}/I{item.EntityName}Rp.cs");
WriteCode(new Dictionary<string, string>
{
{ "%entityName%",item.EntityName},
{ "%namespacePath%",area.RpBulidPath}
}, rpTemplate, $"../../{area.RpBulidPath.Trim().Replace(".", "\\")}/{item.EntityName}Rp.cs");
WriteCode(new Dictionary<string, string>
{
{ "%entityName%",item.EntityName},
{ "%namespacePath%",area.IServiceBulidPath}
}, iServiceTemplate, $"../../{area.IServiceBulidPath.Trim().Replace(".", "\\")}/I{item.EntityName}Service.cs");
WriteCode(new Dictionary<string, string>
{
{ "%entityName%",item.EntityName},
{ "%namespacePath%",area.ServiceBulidPath}
}, service, $"../../{area.ServiceBulidPath.Trim().Replace(".", "\\")}/{item.EntityName}Service.cs");
}
}
return true;
}
/// <summary>
/// 获取对应模板文件
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private string GetBuildCodeTemplate(string name)
{
return File.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>
private void WriteCode(Dictionary<string, string> paramters, string content, string savePath)
{
foreach (var item in paramters)
{
content = content.Replace(item.Key, item.Value);
}
var dir = 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
namespace kevin.CodeGenerator.Dto
{
public class CodeGeneratorSetting
{
/// <summary>
/// 配置文件相关信息
/// </summary>
public List<CodeGeneratorItem> CodeGeneratorItems { get; set; } = new();
}
public class CodeGeneratorItem
{
/// <summary>
/// 区域
/// </summary>
public string AreaName { get; set; } = "";
/// <summary>
/// 数据库实体类路径
/// </summary>
public string AreaPath { get; set; } = "";
/// <summary>
/// 仓储接口生成路径
/// </summary>
public string IRpBulidPath { get; set; } = "";
/// <summary>
/// 仓储生成路径
/// </summary>
public string RpBulidPath { get; set; } = "";
/// <summary>
/// 服务接口生成路径
/// </summary>
public string IServiceBulidPath { get; set; } = "";
/// <summary>
/// 服务生成路径
/// </summary>
public string ServiceBulidPath { 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 =>
{
var settings = Configuration.GetRequiredSection("CodeGeneratorSetting").Get<CodeGeneratorSetting>()!;
options.CodeGeneratorItems = settings.CodeGeneratorItems;
});
使用



浙公网安备 33010602011771号