• .Net Core——用代码写代码?


    想要用代码写代码,肯定是绕不开反射的。反射的概念相比都不陌生,只是应用多少就因人而异,今天分享一个代码生成器的思路,仅供参考,不要过分依赖哦。

    思路分析

    众所周知,利用反射可以在程序运行时获取到任一对象的类型、属性、参数、方法等,并加以调用,利用这些获取到的可以在程序运行时追加各种自定义的功能。以CRUD为例,我们可以利用反射获取到所有的Model并编写代码模板,最终达成用代码生成代码的结果。思路既然能走通,开搞开搞~

    编码阶段

    首先要确定生成哪些代码。CRUD每天都在做,但大部分都一样,这就导致每天有些时间都在板砖,毫无意义。所以我们需要自动生成全库的CRUD代码。

    首先要写一个CRUD的模板代码,考虑到ORM框架太多,这里就以SqlSugar为例:

         [HttpGet]
            public async Task<IActionResult> GetList(int index = 1, int size = 15)
            {
                RefAsync<int> count = 0;
    
                return PageMsg(await _sqlHelper.DB
                    .Queryable<Models.AD>()
                    .OrderBy(x => x.Weight)
                    .ToPageListAsync(index, size, count), count.Value);
            }
    
            [HttpPost, Role("添加广告")]
            public async Task<IActionResult> Add([FromForm] Models.AD ad)
            {
                Models.AD add = await _sqlHelper.DB
                    .Insertable(ad)
                    .RemoveDataCache()
                    .ExecuteReturnEntityAsync();
    
                return Ok(add);
            }
    
            [HttpPut, Role("修改广告")]
            public async Task<IActionResult> Cag([FromForm] Models.AD ad)
            {
           
    int result = await _sqlHelper.DB .Updateable(ad) .RemoveDataCache() .ExecuteCommandAsync();
           
           return
    YesOrNo(result > 0); } [HttpDelete] public async Task<IActionResult> Delete([FromForm] int id) {
           
    int result = await _sqlHelper.DB .Deleteable<Models.AD>() .Where(x => x.ID == id) .ExecuteCommandAsync();
           return YesOrNo(result > 0); }

    能看出这是一组操作AD类的CRUD,接下来就是需要把上面的模板封装起来,AD这种表的名称作为变量输入即可,如果想控制代码文件的路径,也可以作为参数传入。完整版:

         public void Make(string tableName, string path)
            {
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
    
                using FileStream fs = new FileStream($"{path}/{tableName}Controller.cs", FileMode.Append);
    
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                sb.Append("using System.Threading.Tasks;");
                sb.Append("
    ");
                sb.Append("using XXXX.Services.DB;");
                sb.Append("
    ");
                sb.Append("using Microsoft.AspNetCore.Authorization;");
                sb.Append("
    ");
                sb.Append("using Microsoft.AspNetCore.Mvc;");
                sb.Append("
    ");
                sb.Append("using SqlSugar;");
                sb.Append("
    ");
                sb.Append("namespace XXXX.Controllers.v1");
                sb.Append("
    ");
                sb.Append("{");
                sb.Append("
    ");
                sb.Append("     [ApiController, Route("v1/[controller]/[action]"), Authorize]");
                sb.Append("
    ");
                sb.Append($"     public class {tableName}Controller : BaseController");
                sb.Append("
    ");
                sb.Append("     {");
                sb.Append("
    ");
                sb.Append("         private readonly SqlHelper _sqlHelper;");
                sb.Append("
    ");
                sb.Append($"        public {tableName}Controller(SqlHelper sqlHelper)");
                sb.Append("
    ");
                sb.Append("         {");
                sb.Append("
    ");
                sb.Append("             _sqlHelper = sqlHelper;");
                sb.Append("
    ");
                sb.Append("         }");
                sb.Append("
    ");
                sb.Append("         [HttpGet]");
                sb.Append("
    ");
                sb.Append($"         public async Task<IActionResult> GetList(int index = 1, int size = 15)");
                sb.Append("
    ");
                sb.Append("         {");
                sb.Append("
    ");
                sb.Append($"            RefAsync<int> count = 0;");
                sb.Append("
    ");
                sb.Append("             return Ok(new{");
                sb.Append("
    ");
                sb.Append($"               rows = await _sqlHelper.DB.Queryable<Models.{tableName}>().ToPageListAsync(index, size, count),");
                sb.Append("
    ");
                sb.Append("                total = count.Value");
                sb.Append("
    ");
                sb.Append("             });");
                sb.Append("
    ");
                sb.Append("         }");
                sb.Append("
    ");
                sb.Append("         [HttpPost]");
                sb.Append("
    ");
                sb.Append($"         public async Task<IActionResult> Add([FromForm] Models.{tableName} {tableName.ToLower()})");
                sb.Append("
    ");
                sb.Append("         {");
                sb.Append("
    ");
                sb.Append($"             Models.{tableName} add = await _sqlHelper.DB.Insertable({tableName.ToLower()}).RemoveDataCache().ExecuteReturnEntityAsync();");
                sb.Append("
    ");
                sb.Append("              return Ok(add);");
                sb.Append("
    ");
                sb.Append("         }");
                sb.Append("
    ");
                sb.Append("         [HttpPut]");
                sb.Append("
    ");
                sb.Append($"         public async Task<IActionResult> Cag([FromForm] Models.{tableName} {tableName.ToLower()})");
                sb.Append("
    ");
                sb.Append("         {");
                sb.Append("
    ");
                sb.Append($"             int result = await _sqlHelper.DB.Updateable({tableName.ToLower()}).RemoveDataCache().ExecuteCommandAsync();");
                sb.Append("
    ");
                sb.Append("              return YesOrNo(result>0);");
                sb.Append("
    ");
                sb.Append("         }");
                sb.Append("
    ");
                sb.Append("         [HttpDelete]");
                sb.Append("
    ");
                sb.Append($"         public async Task<IActionResult> Cag([FromForm] int id)");
                sb.Append("
    ");
                sb.Append("         {");
                sb.Append("
    ");
                sb.Append($"             int result = await _sqlHelper.DB.Deleteable<Models.{tableName}>().Where(x => x.ID == id).ExecuteCommandAsync();");
                sb.Append("
    ");
                sb.Append("              return YesOrNo(result>0);");
                sb.Append("
    ");
                sb.Append("         }");
                sb.Append("
    ");
                sb.Append("     }");
                sb.Append("
    ");
                sb.Append("}");
    
                using StreamWriter sw = new StreamWriter(fs);
    
                sw.WriteLine(sb.ToString());
            }

    为了方便理解,刻意美化了一下。

    OK,代码模板搞好了,该从哪里拿到所有的Model呢?思路是先加载程序集,然后找到存放Model的命名空间,然后找到命名空间下面所有符合条件的Class,然后就可以拿到具体的名称,从而调用代码模板进行文件生成,像这样:

           var assembly = Assembly.Load("程序集名称");
    
                var types = assembly.ExportedTypes.Where(a => a.FullName.Contains("Model所处的命名空间")).ToList();
    
           //指定
    string path = $"{Directory.GetCurrentDirectory()}/autoCode"; foreach (var item in types) { string tableName = item.FullName.Split('.')[^1]; Make(tableName, path); }

    接下来直接运行,走完以后的结果是这样的:

     随便打开一个文件,是这样的:

     效果还是不错的。

    如果需要更加精细的控制,可以预先在Model设置特性,然后通过判断特性是否存在来决定如何生成代码,举个栗子:

           var assembly = Assembly.Load("程序集名称");
    
                var types = assembly.ExportedTypes.Where(a => a.FullName.Contains("Model所处的命名空间")).ToList();
    
           //指定
                string path = $"{Directory.GetCurrentDirectory()}/autoCode";
    
                foreach (var item in types)
                {
              //获取所有公开属性 foreach (var prop in item.GetProperties())
              {
       MyAttribute attr = method.GetCustomAttribute(typeof(MyAttribute), true) as MyAttribute;
                if(attr is null)
                {
                  //进入这里代表该属性没有附加 MyAttribute
                }
    } }

    当然,还可以获取MyAttribute的属性拿过来进行判断等等。而实际上很多ORM框架也是用类似手段实现Code First、DB First,不过复杂程度比较高。

    这样批量生成代码有点像活字印刷,虽然可以解决大量机械重复的工作,但灵活度还是不够高,人脑还是无法替代的。

    奇技淫巧,见笑了。

    声明:未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
    本文原创发表于博客园,作者为暮城倾心。欢迎转载。Donation(扫码支持作者)↓

    微信
    支付宝
  • 相关阅读:
    iOS关于本地推送
    [转]iOS8 自动调整UITableView和UICollectionView布局
    [转]在Storyboard中使用自定义的segue类型
    iOS 判断来电状态CTCallCenter代码块不执行问题的解决
    centos 用docker搭建elasticsearch 集群
    element-ui 使用upload上传文件并解决跨域问题
    mysql 常见关键字大全和引擎的差异
    Guava---文件操作Files
    springboot这个redies 查看内存信息
    人生也要动态规划
  • 原文地址:https://www.cnblogs.com/muchengqingxin/p/14794292.html
Copyright © 2020-2023  润新知