C# 如何拥有自动递增版本号(Visual Studio)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/826777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to have an auto incrementing version number (Visual Studio)?
提问by esac
I want to store a set of integers that get auto incremented at build time:
我想存储一组在构建时自动递增的整数:
int MajorVersion = 0;
int MinorVersion = 1;
int Revision = 92;
When I compile, it would auto-increment Revision
. When I build the setup project, it would increment MinorVersion
(I'm OK with doing this manually). MajorVersion
would only be incremented manually.
当我编译时,它会自动递增Revision
。当我构建安装项目时,它会增加MinorVersion
(我可以手动执行此操作)。MajorVersion
只会手动增加。
Then I could display a version number in menu Help/About to the user as:
然后我可以在菜单“帮助/关于”中向用户显示一个版本号:
Version: 0.1.92
How can this be achieved?
如何做到这一点?
This question asks not only how to have an auto-incrementing version number, but also how to use that in code which is a more complete answer than others.
这个问题不仅询问如何拥有自动递增的版本号,还询问如何在代码中使用它,这是一个比其他人更完整的答案。
采纳答案by Noel Kennedy
If you add an AssemblyInfoclass to your project and amend the AssemblyVersion
attribute to end with an asterisk, for example:
如果向项目添加AssemblyInfo类并将AssemblyVersion
属性修改为以星号结尾,例如:
[assembly: AssemblyVersion("2.10.*")]
Visual studio will increment the final number for you according to these rules(thanks galets, I had that completely wrong!)
Visual Studio 将根据这些规则为您增加最终数字(感谢 galets,我完全错了!)
To reference this version in code, so you can display it to the user, you use reflection
. For example,
要在代码中引用此版本,以便将其显示给用户,请使用reflection
. 例如,
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
DateTime buildDate = new DateTime(2000, 1, 1)
.AddDays(version.Build).AddSeconds(version.Revision * 2);
string displayableVersion = $"{version} ({buildDate})";
Three important gotchas that you should know
你应该知道的三个重要问题
From @ashes999:
来自@ashes999:
It's also worth noting that if both AssemblyVersion
and AssemblyFileVersion
are specified, you won't see this on your .exe.
还值得注意的是,如果同时指定AssemblyVersion
和AssemblyFileVersion
,您将不会在 .exe 上看到它。
From @BrainSlugs83:
来自@BrainSlugs83:
Setting only the 4th number to be *
can be bad, as the version won't always increment.
The 3rd number is the number of days since the year 2000, and the 4th number is the number of seconds since midnight (divided by 2) [IT IS NOT RANDOM]. So if you built the solution late in a day one day, and early in a day the next day, the later build would have an earlier version number. I recommend always using X.Y.*
instead of X.Y.Z.*
because your version number will ALWAYS increase this way.
仅将第 4 个数字设置为*
可能不好,因为版本不会总是增加。
第三届数字是自2000年以来的天数,和第4号是自午夜(除以2)的秒数[IT不是随机的]。因此,如果您在一天的晚些时候构建解决方案,并且在第二天的早些时候构建解决方案,则较晚的构建将具有较早的版本号。我建议总是使用X.Y.*
而不是X.Y.Z.*
因为你的版本号总是会以这种方式增加。
Newer versions of Visual Studio give this error:
较新版本的 Visual Studio 出现此错误:
(this thread begun in 2009)
The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation.
See this SO answer which explains how to remove determinism(https://stackoverflow.com/a/58101474/1555612)
(这个话题始于 2009 年)
指定的版本字符串包含与确定性不兼容的通配符。从版本字符串中删除通配符,或禁用此编译的确定性。
请参阅此 SO 答案,其中解释了如何消除确定性(https://stackoverflow.com/a/58101474/1555612)
回答by Micah Smith
Use AssemblyInfo.cs
使用 AssemblyInfo.cs
Create the file in App_Code: and fill out the following or use Google for other attribute/property possibilities.
在 App_Code: 中创建文件并填写以下内容或使用 Google 获取其他属性/属性可能性。
AssemblyInfo.cs
装配信息.cs
using System.Reflection;
[assembly: AssemblyDescription("Very useful stuff here.")]
[assembly: AssemblyCompany("companyname")]
[assembly: AssemblyCopyright("Copyright ? me 2009")]
[assembly: AssemblyProduct("NeatProduct")]
[assembly: AssemblyVersion("1.1.*")]
AssemblyVersion being the part you are really after.
AssemblyVersion 是您真正想要的部分。
Then if you are working on a website, in any aspx page, or control, you can add in the <Page> tag, the following:
然后,如果您正在处理网站、任何 aspx 页面或控件,则可以在 <Page> 标记中添加以下内容:
CompilerOptions="<folderpath>\App_Code\AssemblyInfo.cs"
(replacing folderpath with appropriate variable of course).
(当然用适当的变量替换文件夹路径)。
I don't believe you need to add compiler options in any manner for other classes; all the ones in the App_Code should receive the version information when they are compiled.
我认为您不需要以任何方式为其他类添加编译器选项;App_Code 中的所有代码在编译时都应该收到版本信息。
Hope that helps.
希望有帮助。
回答by galets
Here's the quote on AssemblyInfo.cs from MSDN:
You can specify all the values or you can accept the default build number, revision number, or both by using an asterisk (). For example, [assembly:AssemblyVersion("2.3.25.1")] indicates 2 as the major version, 3 as the minor version, 25 as the build number, and 1 as the revision number. A version number such as [assembly:AssemblyVersion("1.2.")] specifies 1 as the major version, 2 as the minor version, and accepts the default build and revision numbers. A version number such as [assembly:AssemblyVersion("1.2.15.*")] specifies 1 as the major version, 2 as the minor version, 15 as the build number, and accepts the default revision number. The default build number increments daily. The default revision number is random
您可以指定所有值,也可以使用星号 ( )接受默认内部版本号、修订号或两者。例如,[assembly:AssemblyVersion("2.3.25.1")] 表示主要版本为 2,次要版本为 3,内部版本号为 25,修订号为 1。诸如 [assembly:AssemblyVersion("1.2.")] 之类的版本号指定 1 作为主要版本,2 作为次要版本,并接受默认的内部版本号和修订版号。诸如 [assembly:AssemblyVersion("1.2.15.*")] 之类的版本号指定 1 作为主要版本,2 作为次要版本,15 作为内部版本号,并接受默认修订号。默认的内部版本号每天都会增加。默认修订号是随机的
This effectively says, if you put a 1.1.* into assembly info, only build number will autoincrement, and it will happen not after every build, but daily. Revision number will change every build, but randomly, rather than in an incrementing fashion.
这有效地表示,如果您将 1.1.* 放入程序集信息中,则只有构建编号会自动递增,并且不会在每次构建后发生,而是每天发生。修订号将更改每个版本,但会随机更改,而不是以递增的方式更改。
This is probably enough for most use cases. If that's not what you're looking for, you're stuck with having to write a script which will autoincrement version # on pre-build step
这对于大多数用例来说可能已经足够了。如果这不是您要查找的内容,那么您将不得不编写一个脚本,该脚本将在预构建步骤中自动递增版本 #
回答by Robert Lewis
You could use the T4 templating mechanism in Visual Studio to generate the required source code from a simple text file:
您可以使用Visual Studio 中的T4 模板机制从简单的文本文件生成所需的源代码:
I wanted to configure version information generation for some .NET projects. It's been a long time since I investigated available options, so I searched around hoping to find some simple way of doing this. What I've found didn't look very encouraging: people write Visual Studio add-ins and custom MsBuild tasks just to obtain one integer number (okay, maybe two). This felt overkill for a small personal project.
The inspiration came from one of the StackOverflow discussions where somebody suggested that T4 templates could do the job. And of course they can. The solution requires a minimal effort and no Visual Studio or build process customization. Here what should be done:
- Create a file with extension ".tt" and place there T4 template that will generate AssemblyVersion and AssemblyFileVersion attributes:
我想为一些 .NET 项目配置版本信息生成。自从我调查可用选项以来已经很长时间了,所以我四处寻找希望找到一些简单的方法来做到这一点。我发现的情况看起来并不令人鼓舞:人们编写 Visual Studio 加载项和自定义 MsBuild 任务只是为了获得一个整数(好吧,也许是两个)。对于一个小型的个人项目来说,这感觉有点过分了。
灵感来自 StackOverflow 讨论之一,有人建议 T4 模板可以完成这项工作。他们当然可以。该解决方案只需最少的工作,无需 Visual Studio 或构建过程自定义。这里应该做什么:
- 创建一个扩展名为“.tt”的文件,并在那里放置 T4 模板,该模板将生成 AssemblyVersion 和 AssemblyFileVersion 属性:
<#@ template language="C#" #>
//
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
//
using System.Reflection;
[assembly: AssemblyVersion("1.0.1.<#= this.RevisionNumber #>")]
[assembly: AssemblyFileVersion("1.0.1.<#= this.RevisionNumber #>")]
<#+
int RevisionNumber = (int)(DateTime.UtcNow - new DateTime(2010,1,1)).TotalDays;
#>
You will have to decide about version number generation algorithm. For me it was sufficient to auto-generate a revision number that is set to the number of days since January 1st, 2010. As you can see, the version generation rule is written in plain C#, so you can easily adjust it to your needs.
- The file above should be placed in one of the projects. I created a new project with just this single file to make version management technique clear. When I build this project (actually I don't even need to build it: saving the file is enough to trigger a Visual Studio action), the following C# is generated:
您将不得不决定版本号生成算法。对我来说,自动生成设置为自 2010 年 1 月 1 日以来的天数的修订号就足够了。 如您所见,版本生成规则是用纯 C# 编写的,因此您可以轻松地根据需要对其进行调整.
- 上面的文件应该放在其中一个项目中。我只用这个文件创建了一个新项目,以明确版本管理技术。当我构建这个项目时(实际上我什至不需要构建它:保存文件足以触发 Visual Studio 操作),会生成以下 C#:
//
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
//
using System.Reflection;
[assembly: AssemblyVersion("1.0.1.113")]
[assembly: AssemblyFileVersion("1.0.1.113")]
Yes, today it's 113 days since January 1st, 2010. Tomorrow the revision number will change.
- Next step is to remove AssemblyVersion and AssemblyFileVersion attributes from AssemblyInfo.cs files in all projects that should share the same auto-generated version information. Instead choose “Add existing item” for each projects, navigate to the folder with T4 template file, select corresponding “.cs” file and add it as a link. That will do!
What I like about this approach is that it is lightweight (no custom MsBuild tasks), and auto-generated version information is not added to source control. And of course using C# for version generation algorithm opens for algorithms of any complexity.
是的,今天是 2010 年 1 月 1 日以来的 113 天。明天修订号会改变。
- 下一步是从所有应共享相同自动生成版本信息的项目中的 AssemblyInfo.cs 文件中删除 AssemblyVersion 和 AssemblyFileVersion 属性。而是为每个项目选择“添加现有项目”,导航到包含 T4 模板文件的文件夹,选择相应的“.cs”文件并将其添加为链接。那行!
我喜欢这种方法的地方在于它是轻量级的(没有自定义 MsBuild 任务),并且不会将自动生成的版本信息添加到源代码管理中。当然,使用 C# 进行版本生成算法适用于任何复杂的算法。
回答by Mun
You could try using UpdateVersion by Matt Griffith. It's quite old now, but works well. To use it, you simply need to setup a pre-build event which points at your AssemblyInfo.cs file, and the application will update the version numbers accordingly, as per the command line arguments.
您可以尝试使用 Matt Griffith 的 UpdateVersion。现在已经很老了,但运行良好。要使用它,您只需设置一个指向您的 AssemblyInfo.cs 文件的预构建事件,应用程序将根据命令行参数相应地更新版本号。
As the application is open-source, I've also created a version to increment the version number using the format (Major version).(Minor version).([year][dayofyear]).(increment). I've put the code for my modified version of the UpdateVersion application on GitHub: https://github.com/munr/UpdateVersion
由于该应用程序是开源的,我还创建了一个版本来使用格式(Major version).(Minor version).([year][dayofyear]).(increment) 增加版本号。我已将我修改后的 UpdateVersion 应用程序的代码放在 GitHub 上:https: //github.com/munr/UpdateVersion
回答by Raymond
You can do more advanced versioning using build scripts such as Build Versioning
您可以使用构建脚本进行更高级的版本控制,例如Build Versioning
回答by gideon
If you put an asterisk in for build and revision visual studio uses the number of days since Jan. 1st 2000 as the build number, and the number of seconds since midnight divided by 2 as the revision.
如果您为构建和修订添加星号,visual studio 使用自 2000 年 1 月 1 日以来的天数作为构建编号,并将自午夜以来的秒数除以 2 作为修订。
A MUCH better life saver solution is http://autobuildversion.codeplex.com/
一个更好的救生解决方案是http://autobuildversion.codeplex.com/
It works like a charm and it's VERY flexible.
它就像一个魅力,它非常灵活。
回答by Drew Chapin
This is my implementation of the T4 suggestion... This will increment the build number every time you build the project regardless of the selected configuration (i.e. Debug|Release), and it will increment the revision number every time you do a Release build. You can continue to update the major and minor version numbers through Application ➤ Assembly Information...
这是我对 T4 建议的实现...无论选择何种配置(即调试|发布),每次构建项目时都会增加构建号,并且每次执行发布构建时都会增加修订号。您可以通过Application ➤ Assembly Information...继续更新主要和次要版本号。
To explain in more detail, this will read the existing AssemblyInfo.cs
file, and use regex to find the AssemblyVersion
information and then increment the revision and build numbers based on input from TextTransform.exe
.
为了更详细地解释,这将读取现有AssemblyInfo.cs
文件,并使用正则表达式查找AssemblyVersion
信息,然后根据来自TextTransform.exe
.
- Delete your existing
AssemblyInfo.cs
file. Create a
AssemblyInfo.tt
file in its place. Visual Studio should createAssemblyInfo.cs
and group it with the T4 file after you save the T4 file.<#@ template debug="true" hostspecific="true" language="C#" #> <#@ output extension=".cs" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Text.RegularExpressions" #> <# string output = File.ReadAllText(this.Host.ResolvePath("AssemblyInfo.cs")); Regex pattern = new Regex("AssemblyVersion\(\"(?<major>\d+)\.(?<minor>\d+)\.(?<revision>\d+)\.(?<build>\d+)\"\)"); MatchCollection matches = pattern.Matches(output); if( matches.Count == 1 ) { major = Convert.ToInt32(matches[0].Groups["major"].Value); minor = Convert.ToInt32(matches[0].Groups["minor"].Value); build = Convert.ToInt32(matches[0].Groups["build"].Value) + 1; revision = Convert.ToInt32(matches[0].Groups["revision"].Value); if( this.Host.ResolveParameterValue("-","-","BuildConfiguration") == "Release" ) revision++; } #> using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Resources; // General Information [assembly: AssemblyTitle("Insert title here")] [assembly: AssemblyDescription("Insert description here")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Insert company here")] [assembly: AssemblyProduct("Insert product here")] [assembly: AssemblyCopyright("Insert copyright here")] [assembly: AssemblyTrademark("Insert trademark here")] [assembly: AssemblyCulture("")] // Version informationr( [assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")] [assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")] [assembly: NeutralResourcesLanguageAttribute( "en-US" )] <#+ int major = 1; int minor = 0; int revision = 0; int build = 0; #>
Add this to your pre-build event:
"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating$(VisualStudioVersion)\TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"
- 删除现有
AssemblyInfo.cs
文件。 AssemblyInfo.tt
在其位置创建一个文件。AssemblyInfo.cs
保存 T4 文件后,Visual Studio 应创建它并将其与 T4 文件分组。<#@ template debug="true" hostspecific="true" language="C#" #> <#@ output extension=".cs" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Text.RegularExpressions" #> <# string output = File.ReadAllText(this.Host.ResolvePath("AssemblyInfo.cs")); Regex pattern = new Regex("AssemblyVersion\(\"(?<major>\d+)\.(?<minor>\d+)\.(?<revision>\d+)\.(?<build>\d+)\"\)"); MatchCollection matches = pattern.Matches(output); if( matches.Count == 1 ) { major = Convert.ToInt32(matches[0].Groups["major"].Value); minor = Convert.ToInt32(matches[0].Groups["minor"].Value); build = Convert.ToInt32(matches[0].Groups["build"].Value) + 1; revision = Convert.ToInt32(matches[0].Groups["revision"].Value); if( this.Host.ResolveParameterValue("-","-","BuildConfiguration") == "Release" ) revision++; } #> using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Resources; // General Information [assembly: AssemblyTitle("Insert title here")] [assembly: AssemblyDescription("Insert description here")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Insert company here")] [assembly: AssemblyProduct("Insert product here")] [assembly: AssemblyCopyright("Insert copyright here")] [assembly: AssemblyTrademark("Insert trademark here")] [assembly: AssemblyCulture("")] // Version informationr( [assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")] [assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")] [assembly: NeutralResourcesLanguageAttribute( "en-US" )] <#+ int major = 1; int minor = 0; int revision = 0; int build = 0; #>
将此添加到您的预构建事件中:
"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating$(VisualStudioVersion)\TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"
回答by Dmi7ry
Star in version (like "2.10.3.*") - it is simple, but the numbers are too large
AutoBuildVersion - looks great but its dont work on my VS2010.
@DrewChapin's script works, but I can not in my studio set different modes for Debug pre-build event and Release pre-build event.
版本中的星号(如“2.10.3.*”) - 很简单,但数字太大
AutoBuildVersion - 看起来不错,但它在我的 VS2010 上不起作用。
@DrewChapin 的脚本有效,但我无法在我的工作室中为 Debug pre-build event 和 Release pre-build event 设置不同的模式。
so I changed the script a bit... commamd:
所以我稍微改变了脚本......命令:
"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating.0\TextTransform.exe" -a !!$(ConfigurationName)!1 "$(ProjectDir)Properties\AssemblyInfo.tt"
and script (this works to the "Debug" and "Release" configurations):
和脚本(这适用于“调试”和“发布”配置):
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
int incRevision = 1;
int incBuild = 1;
try { incRevision = Convert.ToInt32(this.Host.ResolveParameterValue("","","Debug"));} catch( Exception ) { incBuild=0; }
try { incBuild = Convert.ToInt32(this.Host.ResolveParameterValue("","","Release")); } catch( Exception ) { incRevision=0; }
try {
string currentDirectory = Path.GetDirectoryName(Host.TemplateFile);
string assemblyInfo = File.ReadAllText(Path.Combine(currentDirectory,"AssemblyInfo.cs"));
Regex pattern = new Regex("AssemblyVersion\(\"\d+\.\d+\.(?<revision>\d+)\.(?<build>\d+)\"\)");
MatchCollection matches = pattern.Matches(assemblyInfo);
revision = Convert.ToInt32(matches[0].Groups["revision"].Value) + incRevision;
build = Convert.ToInt32(matches[0].Groups["build"].Value) + incBuild;
}
catch( Exception ) { }
#>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Game engine. Keys: F2 (Debug trace), F4 (Fullscreen), Shift+Arrows (Move view). ")]
[assembly: AssemblyProduct("Game engine")]
[assembly: AssemblyDescription("My engine for game")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright ? Name 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. Only Windows
// assemblies support COM.
[assembly: ComVisible(false)]
// On Windows, the following GUID is for the ID of the typelib if this
// project is exposed to COM. On other platforms, it unique identifies the
// title storage container when deploying this assembly to the device.
[assembly: Guid("00000000-0000-0000-0000-000000000000")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.1.<#= this.revision #>.<#= this.build #>")]
[assembly: AssemblyFileVersion("0.1.<#= this.revision #>.<#= this.build #>")]
<#+
int revision = 0;
int build = 0;
#>