我目前有一个应用程序显示构建号在其标题窗口。这很好,除了它对大多数用户没有任何意义,他们想知道他们是否有最新的版本-他们倾向于将其称为“上周四的”而不是1.0.8.4321版本。
计划是把构建日期放在那里,例如“App构建于21/10/2009”。
我正在努力寻找一种程序化的方法,将构建日期作为文本字符串提取出来,以便像这样使用。
对于版本号,我使用:
Assembly.GetExecutingAssembly().GetName().Version.ToString()
在定义了这些是怎么来的之后。
我希望编译日期(和时间,为了加分)也像这样。
非常感谢这里的指示(如果合适的话,借口双关语),或者更整洁的解决方案……
我只是一个c#新手,所以我的回答可能听起来很傻——我从可执行文件最后写入的日期开始显示构建日期:
string w_file = "MyProgram.exe";
string w_directory = Directory.GetCurrentDirectory();
DateTime c3 = File.GetLastWriteTime(System.IO.Path.Combine(w_directory, w_file));
RTB_info.AppendText("Program created at: " + c3.ToString());
我试着用File。GetCreationTime方法,但得到了奇怪的结果:命令的日期是2012-05-29,但窗口资源管理器的日期显示为2012-05-23。在搜索这个差异后,我发现该文件可能是在2012-05-23创建的(如Windows资源管理器所示),但在2012-05-29复制到当前文件夹(如文件所示)。GetCreationTime命令)-所以为了安全起见,我使用文件。GetLastWriteTime命令。
扎莱克
Visual Studio 2019的完整解决方案,就像我几年前开始时希望找到的那样。
添加一个文本资源文件
Access the properties of your project: from the solution explorer, select your project, then right-click -> properties, or Alt+Enter. In the Resources tab, choose Files (Ctrl+5). Then Add Resource / Add New Text File. In the popup message, type the name of your resource, for example BuildDate: this will create a new text file BuildDate.txt in your Project/Resources folder, include it as Project file, and register it as a resource, which can then be accessed via Properties.Resources in C#, or My.Resources in VB.
每次构建时自动更新资源文件
现在,您可以告诉Visual Studio在每次构建或重新构建项目时将日期写入该文件。为此,转到项目属性的编译选项卡,选择生成事件,并复制/粘贴以下内容到“预生成事件命令行”文本框:
powershell -Command "((Get-Date).ToUniversalTime()).ToString(\"s\") | Out-File '$(ProjectDir)Resources\BuildDate.txt'"
这一行将定位BuildDate.txt,并按照ISO8601格式写入today/NowUtc的日期和时间,例如2021-09-07T16:08:35
通过读取文件在运行时获得构建日期
然后你可以在运行时通过下面的助手(c#)从你的代码中检索这个日期:
DateTime CurrentBuildDate = DateTime.Parse(Properties.Resources.BuildDate, null, System.Globalization.DateTimeStyles.RoundtripKind);
学分
基本思路:https://stackoverflow.com/a/15502932/10794555
通过powershell改进:https://stackoverflow.com/users/84898/dbruning
ISO8601的稳定解析:如何从ISO8601格式创建。net DateTime
上面的方法可以对进程中已经加载的程序集进行调整,使用内存中的文件映像(而不是从存储中重新读取它):
using System;
using System.Runtime.InteropServices;
using Assembly = System.Reflection.Assembly;
static class Utils
{
public static DateTime GetLinkerDateTime(this Assembly assembly, TimeZoneInfo tzi = null)
{
// Constants related to the Windows PE file format.
const int PE_HEADER_OFFSET = 60;
const int LINKER_TIMESTAMP_OFFSET = 8;
// Discover the base memory address where our assembly is loaded
var entryModule = assembly.ManifestModule;
var hMod = Marshal.GetHINSTANCE(entryModule);
if (hMod == IntPtr.Zero - 1) throw new Exception("Failed to get HINSTANCE.");
// Read the linker timestamp
var offset = Marshal.ReadInt32(hMod, PE_HEADER_OFFSET);
var secondsSince1970 = Marshal.ReadInt32(hMod, offset + LINKER_TIMESTAMP_OFFSET);
// Convert the timestamp to a DateTime
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var linkTimeUtc = epoch.AddSeconds(secondsSince1970);
var dt = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tzi ?? TimeZoneInfo.Local);
return dt;
}
}