首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

使用.NET源生成器(SG)生成项目的版本号信息

编程知识
2024年09月03日 20:31

之前写过一篇 源生成器生成自动注入的代码 主要是通过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}");
    }
});

image

不难看出项目文件夹和顶级命名空间的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

From:https://www.cnblogs.com/vipwan/p/18395495
本文地址: http://www.shuzixingkong.net/article/1706
0评论
提交 加载更多评论
其他文章 Python批量分割Excel后逐行做差、合并文件的方法
本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,基于其中每一个文件,首先依据某一列数据的特征截取我们需要的数据,随后对截取出来的数据逐行求差,并基于其他多个文件夹中同样大量的Excel表格文件,进行数据跨文件合并的具体方法~
Python批量分割Excel后逐行做差、合并文件的方法 Python批量分割Excel后逐行做差、合并文件的方法 Python批量分割Excel后逐行做差、合并文件的方法
C#设计模式入门实战教程
什么是设计模式 设计模式是对面向对象设计中反复出现的问题的解决方案。它们提供了被反复使用、多数人知晓的、经过分类编目的代码设计经验总结。 设计模式的作用 提高代码的可重用性:通过定义一套标准的解决方案,设计模式使得相同或类似的问题可以在不同的项目中复用相同的代码结构或逻辑。 增强代码的可读性:设计模
C#设计模式入门实战教程 C#设计模式入门实战教程 C#设计模式入门实战教程
我克隆了我自己,数字生命有什么意义?
个人语音模型、个人视频模型、个人LLM语言模型都是基于开源的项目,但是需要进行少量的代码修改和集成的工作,这个过程不说很艰难,但是确实遇到很多问题。
我克隆了我自己,数字生命有什么意义? 我克隆了我自己,数字生命有什么意义? 我克隆了我自己,数字生命有什么意义?
😶‍🌫️ SpringBoot中MongoDB的骚操作用法
不知道大家在工作项目中有没有使用MongoDB,在哪些场景中使用。MongoDB作为NoSQL数据库,不像SQL数据库那样,可以使用Mybatis框架。 如果需要在SpringBoot中使用MongoDB的话,我目前知道有三种方式,第一种是直接使用MongoDB官方的SDK,第二种是使用Spring
😶‍🌫️ SpringBoot中MongoDB的骚操作用法 😶‍🌫️ SpringBoot中MongoDB的骚操作用法 😶‍🌫️ SpringBoot中MongoDB的骚操作用法
CMake构建学习笔记14-依赖库管理工具
如果说做C/C++开发最大的痛点是什么,那么一定是缺少一个官方的统一的包管理器。认真的说,如果你要用C/C++干点什么,至少需要(Windows系统下): C/C++语言本身、标准库、以及操作系统API几乎干不了什么,除非你真的想从零开始造轮子。 开始找一些现成的实现组成依赖库。最好看能不能找到预编
C#自定义控件—文本显示、文本设值
C#用户控件之文本显示、设定组件 如何绘制一个便捷的文本显示组件、文本设值组件(TextShow,TextSet)? 绘制此控件的目的就是方便一键搞定标签显示(可自定义方法显示文本颜色等),方便自定义方法又省略了挨个拖拽的过程 纯定义属性 【文本设定】:字体、标签、值、单位;事件方法:Enter、L
C#自定义控件—文本显示、文本设值
搜索组件优化 - Command ⌘K
今天心血来潮想在 `blog` 上找一篇文章,用搜素的功能发现搜不出来😂,搜索挂了?然后突然想起来之前由于想着在 `blog` 中可能加一些私有的配置或者尝鲜的功能,所有 `fork` 了一份变成 私有项目了,这样就不符合 `DocSearch` 的 网站必须是公开的这个限制了。
搜索组件优化 - Command ⌘K 搜索组件优化 - Command ⌘K 搜索组件优化 - Command ⌘K
英语疑问句倒装特征以及从句的正常语序
上一篇介绍了英文中的五大基本句型,在进一步介绍句子如何在五大句型之上如何各种添枝加叶变得复杂之前,我们先来搞懂英语疑问句倒装特征以及从句的正常语序。 这是至关重要的一件事,但其实太多初学者都给忽略了,在懵圈中苦学了很久,结果在实际应用时产生了各种混乱,事倍而功半。 本文想通过举例的方式,来试图讲清这
英语疑问句倒装特征以及从句的正常语序