首页 > 其他分享 >使用.NET源生成器(SG)生成项目的版本号信息

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

时间:2024-09-03 21:50:15浏览次数:4  
标签:version 版本号 生成器 System Version static var NET public

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

标签:version,版本号,生成器,System,Version,static,var,NET,public
From: https://www.cnblogs.com/vipwan/p/18395495

相关文章

  • cad.net 该死的填充
    捕捉点卡顿cad现在采用了一种密集填充就不显示的策略.系统变量hpmaxlines:默认值100000(十万).其实挺傻的,我们无论何时都要看到填充啊.不然我怎么删掉密集填充呢?不然我还以为没有填充再填充一次呢~它卡顿是发生在画图期间,鼠标经过填充区域密集计算交点,端点...密集计算长......
  • 基于flatten-maven-plugin插件实现maven多模块版本管理,维护为相同版本号
    pom文件引入flatten-maven-plugin插件<build><plugins><!--添加flatten-maven-plugin插件--><plugin><groupId>org.codehaus.mojo</groupId><artifactId>flatten-m......
  • D12 kubernetes 中的资源对象
    1、kubernetes中的资源对象是什么,有什么作用 在Kubernetes中,资源对象是集群内的一个个实体,它们代表了集群的状态和行为。这些资源对象通过Kubernetes的API进行定义和管理,每种资源对象都有特定的作用和用途获取所有的资源kubectlapi-resourcesNAME......
  • 《NET CLR via C#》---第十一章(事件)
    事件成员的类型提供了以下功能:方法能等级它对事件的关注方法能注销它对事件的关注事件发生时,登记的方法将收到通知CLR事件模型以委托为基础。委托是调用回调方法的一种类型安全的方式。对象凭借回调方法接受它们订阅的通知。设计要公开事件的类型在某些情况下,当某个事件......
  • FIT3181: Deep Learning Neural Networks
    FIT3181: Deep Learning (2024)Deep Neural NetworksDue: 11:55pmSunday,8September2024 (Sunday)Important note: This isan individualassignment. Itcontributes25%toyourfinal mark. Readthe assignment instructions carefully.What to s......
  • 【Dash】feffery_antd_componenet 中的 AntdSpace
    一、feffery_antd_componenet中的AntdSpacefeffery_antd_components(简称fac)中的AntdSpace组件是一个基于AntDesign的Dash第三方组件,它用于在水平或垂直方向上放置多个元素,并提供元素之间的间距。以下是AntdSpace组件的一些主要功能:1、设置间距:可以通过size属性来设置元素......
  • 芋道源码微服务新建新的模块及代码生成器使用
    目录概述实践新建模块代码生成配置数据源代码生成拷贝代码pom.xml其它的问题redis权限配置效果结束概述  芋道源码微服务新建新的模块及代码生成器使用。主要分三块,建立新的模块,代码生成及运行过程中的问题解决。实践新建模块  参考芋道源码本身的架构,新......
  • .NET 8.0 前后分离快速开发框架
    https://www.cnblogs.com/1312mn/p/18387692 阅读目录前言项目介绍功能特点适用范围内置功能项目技术项目结构项目效果项目地址最后前言大家好,推荐一个.NET8.0为核心,结合前端Vue框架,实现了前后端完全分离的设计理念。它不仅提供了强大的基础功能支持,如权限......
  • 3GPP R18 Network energy savings(NES) 之cell DTX/DRX
    在TR21.918中可以看到cellDTX/DRX是Networkenergysavings(NES)forNR的一部分,其中还包括SSB-lessSCelloperationforinter-bandCA等等其他内容,其相关描述如下网络节能是5G/NR成功的关键,由此可以减少对环境的影响(温室气体排放)并节省运营成本。RANWG进行了一项......
  • .NET 最好用的验证组件 FluentValidation
    前言一个.NET验证框架,支持链式操作,易于理解,功能完善,组件内提供十几种常用验证器,可扩展性好,支持自定义验证器,支持本地化多语言。项目介绍FluentValidation是一个开源的.NET库,用于验证对象的属性。它提供了一种简单而强大的方式来定义和执行验证规则,使验证逻辑的编写和维护......