尝试在C#w / Visual Studio 2010中创建自动版本控制系统

时间:2013-01-22 17:10:35

标签: c# visual-studio version-control

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

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

//...

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

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

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

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

3 个答案:

答案 0 :(得分: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,您可以添加字段而不会破坏以前的版本。

答案 1 :(得分:2)

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

TFS示例:Keyword Substitution / Expansion Check-In Policy

答案 2 :(得分:1)

在我的脑海中,或者创建一个构建转换 T4 ,它将.cs /类型名称的类/字典构建为hash / timestamp,或者将该属性标记化并挂钩到MSBuild的 BeforeBuild 事件在使用类似的hash / lastmodified编译之前替换它。

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

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将获取文件的哈希值,并在前一个不匹配的情况下更新计数器。

在这些例子中可以做得更好,但希望他们能够说明你可以采取的方向。可能有一个更好的方法,那些是在使用Mono.Cecil对IL进行哈希处理之后的两个想法,我发现这个问题非常有趣。如果你选择了这两条路线,我建议你阅读T4及其Host,以及如何在构建时强制重建,或者MSBuild和扩展事件,自定义和内联任务,甚至可以进入EnvDTE,{{1 },CodeDOM命名空间等,而不仅仅是搜索.cs文件和重新编辑。