之前写过一篇 源生成器生成自动注入的代码 主要是通过SyntaxProvider查找标注特性实现

其实除了SyntaxProvider之外还有几个很重要的Provider,比如:MetadataReferencesProvider,AdditionalTextsProvider,AnalyzerConfigOptionsProvider等.

今天就讲一下AnalyzerConfigOptionsProvider这个Provider,这里通过AnalyzerConfigOptionsProvider获取引用项目文件夹和顶级命名空间:

通过下面的代码我们就可以打印出来引用项目的GlobalOptions:

var projectKeysProvider = context.AnalyzerConfigOptionsProvider
.Select((options, _) =>
{
var keys = options.GlobalOptions.Keys;
List<(string? Key, string? Value)> keyValues = [];
foreach (var key in keys)
{
options.GlobalOptions.TryGetValue(key, out var value);
keyValues.Add((key, value));
}
return keyValues;
});
context.RegisterSourceOutput(projectKeysProvider, (ctx, projectKeys) =>
{
// 生成代码
StringBuilder stringBuilder = new();
foreach (var (Key, Value) in projectKeys)
{
stringBuilder.AppendLine($"// {Key} {Value}");
}
});

不难看出项目文件夹和顶级命名空间的key为build_property.projectdir,build_property.rootnamespace,

取到了项目文件夹地址我们就可以读取对应的*.csproj项目文件了.这里我们通过IO读取文件并取到配置的AssemblyVersion,FileVersion,Version项,然后就可以生成版本信息了,

项目文件本身是一个Xml文件,因此读取配置项可以使用XPath或者正则表达式,出于简洁高效,这里我使用的正则表达式获取:


//生成版本号
var inc = context.AnalyzerConfigOptionsProvider.Select((pvd, _) =>
{
//取得项目目录
var flag = pvd.GlobalOptions.TryGetValue("build_property.projectdir", out var root);
if (!flag)
return new VersionInfo(null, null); //取得命名空间
pvd.GlobalOptions.TryGetValue("build_property.rootnamespace", out var @namespace); //var file = Path.Combine(root, $"*.csproj");
//查找csproj文件
var files = Directory.GetFiles(root, "*.csproj", SearchOption.TopDirectoryOnly); return new VersionInfo(@namespace, files.Length == 0 ? null : files[0]);
}); //生成
context.RegisterSourceOutput(inc, (ctx, info) =>
{
if (info.Namespace == null || info.File == null)
return; string version = DefaultVersion;
string fileVersion = DefaultVersion;
string assemblyVersion = DefaultVersion; // 获取不含扩展名的文件名
//var @namespace = Path.GetFileNameWithoutExtension(info.Item2); // 读取文件
var text = File.ReadAllText(info.File); // 载入Import的文件,例如 : <Import Project="..\Version.props" />
// 使用正则表达式匹配Project:
var importMatchs = Regex.Matches(text, "<Import Project=\"(.*?)\""); foreach (Match importMatch in importMatchs)
{
var importFile = Path.Combine(Path.GetDirectoryName(info.File), importMatch.Groups[1].Value);
if (File.Exists(importFile))
{
text += File.ReadAllText(importFile);
}
} var match = Regex.Match(text, "<Version>(.*?)</Version>");
var fileVersionMatch = Regex.Match(text, "<FileVersion>(.*?)</FileVersion>");
var assemblyVersionMatch = Regex.Match(text, "<AssemblyVersion>(.*?)</AssemblyVersion>");
if (match.Success)
{
version = match.Groups[1].Value;
}
if (fileVersionMatch.Success)
{
fileVersion = fileVersionMatch.Groups[1].Value;
}
if (assemblyVersionMatch.Success)
{
assemblyVersion = assemblyVersionMatch.Groups[1].Value;
} string source = $@"// <auto-generated/>
namespace {info.Namespace}.Generated
{{
/// <summary>
/// The version class
/// </summary>
public static class Version
{{
/// <summary>
/// The current version
/// </summary>
public static System.Version Current => System.Version.Parse(""{version}""); /// <summary>
/// The file version
/// </summary>
public static System.Version FileVersion => System.Version.Parse(""{fileVersion}""); /// <summary>
/// The assembly version
/// </summary>
public static System.Version AssemblyVersion => System.Version.Parse(""{assemblyVersion}""); }}
}}
";
// 输出代码
ctx.AddSource("version.g.cs", SourceText.From(source, Encoding.UTF8));
});

然后就生成了需要的内容:

// <auto-generated/>
namespace Biwen.QuickApi.Generated
{
/// <summary>
/// The version class
/// </summary>
public static class Version
{
/// <summary>
/// The current version
/// </summary>
public static System.Version Current => System.Version.Parse("2.0.0"); /// <summary>
/// The file version
/// </summary>
public static System.Version FileVersion => System.Version.Parse("2.0.0"); /// <summary>
/// The assembly version
/// </summary>
public static System.Version AssemblyVersion => System.Version.Parse("2.0.0"); }
}

最后通过{namespace}.Generated.Version.*就可以取得版本信息了

透过上面的代码我们理论上就可以读取项目文件夹下所有文件的内容了,当然除了AnalyzerConfigOptionsProvider外,我们也可以使用AdditionalTextsProvider读取附加文件的内容,由于当前文章不涉及有时间我再讲!

以上代码就完成了整个源生成步骤,最后你可以使用我发布的nuget包体验:

dotnet add package Biwen.AutoClassGen

源代码我发布到了GitHub,欢迎star! https://github.com/vipwan/Biwen.AutoClassGen

https://github.com/vipwan/Biwen.AutoClassGen/blob/master/Biwen.AutoClassGen.Gen/VersionSourceGenerator.cs

使用.NET源生成器(SG)生成项目的版本号信息的更多相关文章

  1. CommunityToolkit.Mvvm8.1 viewmodel源生成器写法(3)

    本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址 ...

  2. vs2015 生成项目时,提示执行失败,参数错误

    今天vs2015 生成项目时,提示执行失败,参数错误.查了很多资料未解决 后来,发现只有一个项目出现这个问题,其他项目生成正常.怀疑是该项目解决方案的问题 于是将解决项目中的项目移除,逐一生成引用,解 ...

  3. Maven使用archetype迅速生成项目骨架

    archetype意思是"原型",相当于项目模板.archetype是maven的一个插件,相当于模板工具包. 一个十分重要的mvn指令:mvn 插件名:目标名maven自带三个内 ...

  4. Maven之自定义archetype生成项目骨架(一)

      Maven之自定义archetype生成项目骨架(一) 标签: mavennexus插件 2015-07-15 16:40 2443人阅读 评论(0) 收藏 举报  分类: Maven技术(9)  ...

  5. maven3实战之maven使用入门(使用archetype生成项目骨架)

    maven3实战之maven使用入门(使用archetype生成项目骨架) ---------- maven提供了archetype以帮助我们快速勾勒出项目骨架.以Hello World为例,我们使用 ...

  6. .net 做工作流时,生成项目后工具箱里有关工作流的东西不显示解决方法

    在做工作流模块时,遇到一个比较棘手的问题,那就是生成项目后工具箱里有关工作流的东西不显示,这个问题令人百思不得其解,经过查阅英文网站,终于找到解决方法: 把项目中的建模项目移除掉,再重新生成,奇迹出现 ...

  7. Visual Studio总是在重新生成项目?

    你是否曾经有过这种感觉:即使代码没有改变,Visual Studio也总是在重新生成项目? 我们可以生成一个项目,然后不做任何处理后再次生成,我们就可以看见--VS正在开始生成项目,而我的项目代码并没 ...

  8. Maven之自定义archetype生成项目骨架

    Maven之自定义archetype生成项目骨架(一) http://blog.csdn.net/sxdtzhaoxinguo/article/details/46895013

  9. VS生成项目时,有些文件无法复制到输出目录的解决办法

    有时候,我们在生成项目时,发现有些文件如:.jpg的图片文件,无法复制到输出目录中,此时会非常纠结,反复的清理项目,重新生成,依旧不能解决此问题.后来我打开.csproj的项目工程文件时,经过对比发现 ...

  10. 定制Maven原型生成项目

    1自定义原型 1.1创建原型项目 要定制自己的原型,首先就要创建原型项目来进行定制: mvnarchetype:create -DgroupId=com.cdai.arche -DartifactId ...

随机推荐

  1. CF1864F 题解

    写了一小时结果被卡常了(笑. 考虑新加入一个数什么时候会产生贡献,或者什么时候不会产生贡献. 发现当一个数的位置与他前一次出现时的位置所构成的区间内假若有一个比它小的数那么就不得不对这个数新进行一次操 ...

  2. [oeasy]python0010_hello_world_unix_c历史迷因

    ​ Hello World! 回忆上次内容 我们这次设置了断点 设置断点的目的是更快地调试 调试的目的是去除 ​​bug​​ 别害怕 ​​bug​​ 一步步地总能找到 ​​bug​​ 这就是程序员基本 ...

  3. 记录荒废了三年的四年.net开发的第二次面试(进复试了)

    这次面试的是小公司,深圳计通智能,面试分为初试和复试.使用腾讯视频会议完成.相比与上次面试,这次有所进步,进复试了.当然,这可能也与面试风格有关.这次面试着重与项目经历和技术,因此回答比较顺畅. 这一 ...

  4. 用.Net实现GraphRag:从零开始构建智能知识图谱

    近来,大模型技术日新月异,使得与其相关的研发项目也层出不穷.其中一个备受关注的技术便是RAG(Retrieval Augmented Generation).今天,我要跟大家分享一个出色的项目:Gra ...

  5. Jmeter函数助手10-regexFunction

    regexFunction函数用于对上一个请求进行正则表达式提取处理,类似正则表达式. 用于从前一个请求搜索结果的正则表达式:填入正则表达式 Template for the replacement ...

  6. 02 IO口的操作

    目录 前言 一.IO的概念 1.IO接口 2.IO端口 二.CPU和外设进行数据传输的方法 1.程序控制方式 1.1 无条件 1.2 查询方式 2.中断方式 3.DMA方式 一.方法介绍和代码编写 1 ...

  7. 【WSDL】01 JAX-WS 入门案例

    去年这个时候工作遇见时暂时总结的笔记: https://www.cnblogs.com/mindzone/p/14777493.html 当时也不是很清楚,直到最近前同事又遇上了这项技术, 除了WSD ...

  8. 【SpringMVC】09 对JSON的应用

    前面JavaWeb的JSON回顾: https://www.cnblogs.com/mindzone/p/12820877.html 上面的这个帖子我都还没有实际写进Servlet使用,要Mark一下 ...

  9. 【Git】05 分支管理

    查看所有分支: git branch Git将列出所有分支,如果是当前使用的分支,前面会加一个星号表示 创建一个新的分支: git branch 分支名称 创建一个分支并且指向该分支: git che ...

  10. 【转载】 传统PID算法解决不了的情况,应该怎么办?

    原文地址: http://www.51hei.com/bbs/dpj-152844-1.html --------------------------------------------------- ...