导读:本期聚焦于小伙伴创作的《C#怎么获取程序的编译时间?如何读取程序集属性信息?》,敬请观看详情。想在C#程序里动态显示自身的编译时间,却不清楚该从哪里取值?实际上编译时间并未直接暴露为标准属性,但可通过程序集的自定义特性与生成事件来落地。本文先说明程序集清单里内置的版本、公司名等元数据的读取方式,再给出在构建时把当前时间写入AssemblyInfo或源文件的具体做法,最后演示如何用反射加载自定义特性并转为可读字符串。相比手动维护版本文本,这种方案能保证时间随每次生成自动更新,也便于做关于框、日志头信息以及热更新校验,避免人为漏改导致的版本混乱。

在C#开发中,我们经常需要在界面关于框、日志文件头或者调试信息中展示当前程序自身的编译时间,同时也会频繁读取程序集的内置属性,例如版本号、产品名称和描述等。这些信息都存放在程序集的清单里,通过反射即可在运行时获取。除此之外,编译时间本身并不是.NET默认提供的标准特性,需要借助生成事件或源代码生成器在编译阶段写入自定义特性,才能在后期读取。

C#怎么获取程序的编译时间?如何读取程序集属性信息?

一、读取程序集的标准属性信息

每一个C#项目在编译后都会生成包含元数据的程序集(DLL或EXE)。这些元数据中的大部分来自项目文件中的属性或者传统的 AssemblyInfo.cs 文件。我们可以通过 System.Reflection 命名空间下的 Assembly 类来获取当前执行程序集的实例,再访问其对应属性。

下面是一段读取常见程序集属性的示例代码。注意代码中的小于号和大于号都已经做了转义处理,以保证在HTML环境下也能正确展示。

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        Assembly asm = Assembly.GetExecutingAssembly();

        // 程序集标题
        var titleAttr = (AssemblyTitleAttribute)Attribute.GetCustomAttribute(
            asm, typeof(AssemblyTitleAttribute));
        // 程序集版本
        Version ver = asm.GetName().Version;
        // 产品名称
        var productAttr = (AssemblyProductAttribute)Attribute.GetCustomAttribute(
            asm, typeof(AssemblyProductAttribute));

        Console.WriteLine("标题: " + (titleAttr != null ? titleAttr.Title : "无"));
        Console.WriteLine("版本: " + ver.ToString());
        Console.WriteLine("产品: " + (productAttr != null ? productAttr.Product : "无"));
    }
}

上面的代码使用了 Assembly.GetExecutingAssembly() 获取正在运行的程序集,然后通过 Attribute.GetCustomAttribute 方法取得具体的特性对象。对于版本号,直接调用 GetName().Version 即可,无需额外特性查询。

这种方式的优点是简单、稳定,且不需要额外配置,只要项目里设置了对应的程序集属性就能读到。缺点是它只能读取.NET已经定义好的那几个特性,像编译时间这种需求就必须自己扩展。

二、在编译时写入编译时间

由于程序集本身不自带编译时间,我们通常在构建阶段利用预生成事件或源生成器把当前时间写进一个自定义特性类。最简单实用的方法是在项目文件里添加生成事件命令行,让编译前自动生成一个包含当前UTC时间的C#源文件。

假设我们定义了一个名为 BuildTimeAttribute 的特性,放在项目的 Common 命名空间下,然后在 csproj 文件中使用 BeforeBuild 目标来写文件。示例 csproj 片段如下:

<Target Name="BeforeBuild">
  <WriteLinesToFile
    File="$(IntermediateOutputPath)BuildTime.g.cs"
    Lines="using System; namespace Common { [AttributeUsage(AttributeTargets.Assembly)] public sealed class BuildTimeAttribute : Attribute { public BuildTimeAttribute(string time) { Time = time; } public string Time { get; } } }"
    Overwrite="true" />
  <WriteLinesToFile
    File="$(IntermediateOutputPath)BuildTime.g.cs"
    Lines="[assembly: Common.BuildTimeAttribute("$([System.DateTime]::UtcNow.ToString("yyyy-MM-dd HH:mm:ss"))")]"
    Overwrite="false" />
</Target>

这段代码在每次生成前都会重新写出 BuildTime.g.cs,其中包含了当前UTC时间字符串,并以程序集特性形式附着到产物上。使用 $([System.DateTime]::UtcNow) 可以保证时间随编译动作自动刷新,不需要开发者手动改代码。

相比在代码里硬编码一个日期常量,这种做法完全自动化,也不会因为忘记修改而导致关于界面显示旧时间。要注意的是,如果团队使用确定性构建(Deterministic),某些场景下时间戳可能被忽略,此时应改用源生成器或在CI脚本中显式传入时间参数。

三、读取自定义编译时间特性

写入之后,读取就只是普通的反射操作。我们复用前面提到的 Attribute.GetCustomAttribute 方法,只是类型换成自己定义的 BuildTimeAttribute。

using System;
using System.Reflection;
using Common;

class InfoReader
{
    public static string GetBuildTime()
    {
        Assembly asm = Assembly.GetExecutingAssembly();
        var attr = (BuildTimeAttribute)Attribute.GetCustomAttribute(
            asm, typeof(BuildTimeAttribute));
        if (attr == null)
            return "未知";
        return attr.Time;
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine("本程序编译时间: " + InfoReader.GetBuildTime());
    }
}

上述代码中,InfoReader.GetBuildTime 方法尝试从执行程序集中取出 BuildTimeAttribute,如果找不到就返回“未知”。找到后直接读取其 Time 属性即可得到生成时写入的时间文本。

为了兼容不同时区,建议在写入阶段统一使用UTC,在展示时再根据用户本地时区转换。例如可把字符串解析为 DateTime 后再调用 ToLocalTime。这样既能保证构建服务器与开发者机器时间一致,也能在客户端显示符合习惯的时间。

四、通过程序集元数据做更多事情

除了编译时间,程序集属性还能承载很多有用的信息,比如提交哈希、构建编号、运行环境要求等。我们可以把这些内容都做成自定义特性,然后在程序启动时统一收集,输出到日志或者系统信息接口里。

下面用一张表总结常见程序集属性及获取方式:

属性名称对应特性类获取方式
程序集标题AssemblyTitleAttributeAttribute.GetCustomAttribute
版本号内置清单Assembly.GetName().Version
公司名称AssemblyCompanyAttributeAttribute.GetCustomAttribute
编译时间自定义BuildTimeAttributeAttribute.GetCustomAttribute

借助这套机制,我们不仅能回答“C#怎么获取程序的编译时间”的问题,还能把整个程序集的属性读取封装成一个通用工具类,在多个项目中复用。对于需要远程诊断的客户端软件,把编译时间与版本号随错误报告一起上报,可以大幅降低排查成本。

最后提醒一点,程序集特性在反射时会有轻微性能开销,若高频调用建议缓存结果。例如在静态构造函数里读取一次编译时间并保存为只读字段,后续直接返回字段值,既满足需求又不影响运行效率。

C#程序集属性编译时间修改时间:2026-08-09 05:36:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。