1

所以我有大量的类,当一个类更新时,我需要对任何现有的保存数据运行更新方法。目前我使用类似的东西:

public const decimal LatestVersion = 0.0121201313m;
private decimal LastVersion;

//...

if (Abilities.LastVersion != Abilities.LatestVersion)
{
    //...

每次更新课程时,我都会手动更新最新版本号......我还必须在每个可能需要更新的课程中重复此方法。它运作良好,但我必须记住更新版本号。

如果类被更改或类似的东西,我认为最好让 LatestVersion 自动更新到当前版本DateTime(可能通过调试命令)......但我认为这是不可能的。

有没有人对我如何在类级别设置自动实现版本控制系统有任何其他想法?

4

3 回答 3

2

您可以在类文件中使用某种非空白内容的哈希值作为版本。每个类需要 2 个文件 - 一个源,一个在构建时生成,但会保证任何更改都会更改版本。可能需要在哈希中添加日期以防万一。

 // source file MyClass.cs
 partial class MyClass {}

 // MyClass.Hash.cs
 // generate during build via custom tool 
 partial class MyClass 
 {
    // hash of MyClass.cs + date
    public static string LatestVersion = "W#$@WW-2012-01-22"; 
 }

旁注:

  • 自动系统可能比手动更改版本更糟糕,测试验证更改是否兼容。
  • 您可以考虑以对更改更宽容的格式保存数据。即使用 JSON/XML,您可以在不破坏以前版本的情况下添加字段。
于 2013-01-22T17:22:10.383 回答
2

一些版本控制系统可以使用关键字扩展机制。您可以使用它在签入或签出期间将更改/序列号/修订号(或任何名称)放入文件中。

TFS 示例:关键字替换/扩展签入策略

于 2013-01-22T17:43:27.873 回答
1

在我的脑海中,要么创建一个构建时的转换T4,它将 .cs/type 名称的类/字典构建为哈希/时间戳,或者将该属性标记并挂钩到 MSBuild 的BeforeBuild事件以在编译之前将其替换为类似哈希/上次修改。

编辑:好的,这里有几个非常粗略的例子。

T4 -- 在您的项目 (.tt) 中创建一个文本模板并粘贴以下内容

<#@ template hostspecific="true" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
namespace ClassLibrary1
{
    public class Version
    {
        <#  var project = new FileInfo(Host.ResolvePath("ClassLibrary1.csproj"));
            WriteLine("// " + project.FullName);

            var files = project.Directory.GetFileSystemInfos("*.cs", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var name = Path.GetFileNameWithoutExtension(file.Name);
                if (name == "Version")
                    continue; #>
               public const long <#= name #> = <#= file.LastWriteTime.Ticks #>;
        <#  } #>
    }
}

您现在将拥有一个可以通过 Version.ClassName 常量在比较中使用的类。

MSBuild - 编辑您的 .csproj 并在末尾添加以下内容。

<UsingTask TaskName="Version" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
  <ParameterGroup>
    <Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
  </ParameterGroup>
  <Task>
    <Using Namespace="System.IO" />
    <Using Namespace="System.Text.RegularExpressions" />
    <Code Type="Fragment" Language="cs"><![CDATA[
          var regex = new Regex(@"Version = (\d+);//(-?\d+)");
          foreach (var file in Files)
          {
              var source = File.ReadAllText(file.ItemSpec);
              var match = regex.Match(source);
              if (!match.Success) continue;
              var hash = regex.Replace(source, string.Empty).GetHashCode();
              if (int.Parse(match.Groups[2].Value) == hash) continue;
              source = regex.Replace(source, string.Format("Version = {0};//{1}", int.Parse(match.Groups[1].Value) + 1, hash));
              File.WriteAllText(file.ItemSpec, source);
          }
      ]]></Code>
  </Task>
</UsingTask>
<Target Name="BeforeBuild">
  <Version Files="@(Compile)" />
</Target>

然后添加public const int Version = 0;//0到您的班级。在编译之前,MSBuild 将获取文件的哈希值,如果前一个不匹配,则更新计数器。

在这些示例中有一个可以做得更好的 crapton,但希望它们能说明您可以采取的方向。可能有更好的方法,这是在使用 Mono.Cecil 对 IL 进行哈希处理后突然出现在我脑海中的前两个想法,我发现这个问题很有趣。如果您确实走任何一条路线,我建议您阅读 T4 及其Host以及如何在构建时强制重新生成,或 MSBuild 和扩展事件、自定义和内联任务,甚至可能进入EnvDTE, CodeDOM,Microsoft.Build.Evaluation命名空间等,而不仅仅是搜索 .cs 文件和正则表达式。

于 2013-01-22T18:59:56.733 回答