关于c#:如何获得自动递增版本号(Visual Studio)?

How to have an auto incrementing version number (Visual Studio)?

本问题已经有最佳答案,请猛点这里访问。

我要存储一组在生成时自动递增的整数:

1
2
3
int MajorVersion = 0;
int MinorVersion = 1;
int Revision = 92;

当我编译时,它会自动增加Revision。当我构建安装项目时,它将增加MinorVersion(我可以手动进行)。MajorVersion只能手动递增。

然后我可以在菜单帮助/关于中向用户显示版本号,如下所示:

1
  Version: 0.1.92

如何实现这一目标?

这个问题不仅要求如何拥有一个自动递增的版本号,而且还要求如何在代码中使用这个版本号,这是一个比其他版本更完整的答案。


如果将assemblyinfo类添加到项目中并将assemblyversion属性修改为以星号结尾,例如:

1
[assembly: AssemblyVersion("2.10.*")]

Visual Studio将根据这些规则为您增加最终的数字(感谢Galets,我完全弄错了!)

要在代码中引用此版本,以便向用户显示它,可以使用反射。例如,

1
2
3
4
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})";

。你应该知道的两个重要问题来自@ashes999:

同样值得注意的是,如果同时指定了AssemblyVersionAssemblyFileVersion,则在.exe上不会看到此内容。

来自@brainslags83:

将第四个数字设置为*可能不好,因为版本不会总是递增。第3个数字是2000年以来的天数,第4个数字是午夜以来的秒数(除以2)[不是随机的]。因此,如果您在某一天的晚些时候构建解决方案,而在第二天的早一天构建解决方案,那么晚一天的构建将具有较早的版本号。我建议总是使用X.Y.*而不是X.Y.Z.*,因为您的版本号总是这样增加。


您可以使用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:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <#@ 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:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    //
    // 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.


    这是我对T4建议的实施…这将在每次构建项目时增加内部版本号,而不考虑所选的配置(即调试版本),并且在每次进行发布构建时都会增加修订号。您可以通过应用程序和程序集信息继续更新主要和次要版本号…

    为了更详细地解释,将读取现有的AssemblyInfo.cs文件,并使用regex查找AssemblyVersion信息,然后根据TextTransform.exe的输入增加修订和构建编号。

  • 删除现有的AssemblyInfo.cs文件。
  • 在其位置创建一个AssemblyInfo.tt文件。在保存t4文件后,Visual Studio应该创建AssemblyInfo.cs并将其与t4文件分组。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    <#@ 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;
    #>
  • 将此添加到预生成事件:

    1
    "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe" -a !!BuildConfiguration!$(Configuration)"$(ProjectDir)Properties\AssemblyInfo.tt"


  • 如果在for build and revision中输入星号,则Visual Studio使用自2000年1月1日起的天数作为内部版本号,使用自午夜起的秒数除以2作为内部版本号。

    一个更好的救生方案是http://autobuildversion.codeplex.com。/

    它就像一个魅力,而且非常灵活。


    以下是来自msdn的assemblyinfo.cs的报价:

    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

    这实际上意味着,如果将1.1.*放到程序集信息中,只有内部版本号将自动递增,并且它不会在每次生成之后发生,而是每天发生。修订号将更改每个构建,但是随机的,而不是以递增的方式。

    对于大多数用例来说,这可能已经足够了。如果这不是您要找的,那么您必须编写一个脚本,该脚本将在预构建步骤上自动增加版本。


    使用assemblyinfo.cs

    在app_code中创建文件:并填写以下内容或使用Google获取其他属性/属性。

    汇编信息.cs

    1
    2
    3
    4
    5
    6
    7
    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是您真正需要的部分。

    然后,如果您在网站、任何ASPX页面或控件中工作,则可以添加标记,如下所示:

    1
    CompilerOptions="<folderpath>\App_Code\AssemblyInfo.cs"

    (当然,用适当的变量替换folderPath)。

    我认为您不需要以任何方式为其他类添加编译器选项;应用程序代码中的所有类在编译时都应该收到版本信息。

    希望有帮助。


    • 星型版本(如"2.10.3.*")—很简单,但数字太大

    • AutobuildVersion-看起来不错,但在我的VS2010上不起作用。

    • @Drewchapin的脚本可以工作,但是我不能在我的工作室中为调试预生成事件和发布预生成事件设置不同的模式。

    所以我把剧本改了一点…通信:

    1
    "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\10.0\TextTransform.exe" -a !!$(ConfigurationName)!1"$(ProjectDir)Properties\AssemblyInfo.tt"

    和脚本(这适用于"调试"和"发布"配置):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    <#@ 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;
    #>


    您可以尝试使用Matt Griffith的UpdateVersion。现在已经很旧了,但效果很好。要使用它,只需设置一个指向assemblyinfo.cs文件的预生成事件,应用程序将根据命令行参数相应地更新版本号。

    由于应用程序是开源的,我还创建了一个版本来使用格式(主版本)来增加版本号。(次版本)。([年][年][日])(增量)。有关此和修订代码的详细信息,请参阅我的日志、程序集版本号和.NET。

    更新:我已将更新版本应用程序的修改版本的代码放在GitHub上:https://github.com/muner/updateVersion


    您可以使用构建脚本(如构建版本控制)执行更高级的版本控制。