views:

876

answers:

7

In C# 3.0, I have a property which is suppose to contain the version of the class. The version number is simply the date and time of compilation. Right now, I have the following code:

public DateTime Version
{
    get { return DateTime.UtcNow; }
}

Obviously, this is wrong since this property returns me the current date and time. So, is the precompiler can print the DateTime at compile time? In this case, I could do something similar to below.

public DateTime Version
{
    get { return new DateTime("PRECOMPILER DATE"); }
}

Thanks!

+7  A: 

C# doesn't have the concept of macros; however, you can use other tools in your build script (csproj / NANT / etc) to manipulate the source before it compiles. I use this, for example, to set the revision number to the current SVN revision.

A cheap option is a pre-build event (you can do this via the project properties dialog in VS): essentially a bat file that runs before build; you can then script whatever changes you need. A more sophisticated option is build tasks.

For example, the utility library here includes a Time task and a FileUpdate task; it should (in theory) be possible to chain the two together to emulate what you need.

Personally, I'd use the [AssemblyVersion] details rather than the time - if you link this to your source-control system, this makes it very easy to find the offending version; so for my SVN version, I then use (in my build proj):

<!-- See http://msbuildtasks.tigris.org -->
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
...
<SvnInfo LocalPath=".">
  <Output TaskParameter="Revision" PropertyName="BuildRev" />
</SvnInfo>
...
<FileUpdate Files="Path\To\My\AssemblyInfo.cs"
    Regex='(\[\s*assembly:\s*AssemblyVersion\(\s*"[^\.]+\.[^\.]+)\.([^\.]+)(\.)([^\.]+)("\)\s*\])'
    ReplacementText='$1.$2.$(BuildRev)$5' />
<FileUpdate Files="Path\To\My\AssemblyInfo.cs"
    Regex='(\[\s*assembly:\s*AssemblyFileVersion\(\s*"[^\.]+\.[^\.]+)\.([^\.]+)(\.)([^\.]+)("\)\s*\])'
    ReplacementText='$1.$2.$(BuildRev)$5' />

And now my assembly-version is correct, including the file-version that gets reported by the OS.

Marc Gravell
I do something similiar to this in MSBuild using the Microsoft SDC tasks at: http://www.codeplex.com/sdctasks
Ray Booysen
+2  A: 

There's no equivalent for the __TIME__ preprocessor directive in C#, The best you could do is get the current assembly and get the created date, it will contain the compile time. See here

Jesse Pepper
A: 

I don't think there's a way to do this in C# - C++ style macro definitions are explictly disallowed.

You could work around it using either the last modified date of the assembly, or potentially include a text file as an embedded resource and add a custom build action that writes the current date/time into it.

Steven Robbins
A: 

There's no preprocessor __TIME__ directive, but there's other things you could use, such as the creation time of the assembly. You might also consider using keyword substitution from your source control system ($Date$ in subversion).

Stewart Johnson
+5  A: 

You can retreive it from the dll itself (Source: codinghorror)

   private DateTime RetrieveLinkerTimestamp() {
        string filePath = System.Reflection.Assembly.GetCallingAssembly().Location;
        const int c_PeHeaderOffset = 60;
        const int c_LinkerTimestampOffset = 8;
        byte[] b = new byte[2048];
        System.IO.Stream s = null;

        try {
            s = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            s.Read(b, 0, 2048);
        } finally {
            if (s != null) {
                s.Close();
            }
        }

        int i = System.BitConverter.ToInt32(b, c_PeHeaderOffset);
        int secondsSince1970 = System.BitConverter.ToInt32(b, i + c_LinkerTimestampOffset);
        DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
        dt = dt.AddSeconds(secondsSince1970);
        dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours);
        return dt;
    }
Stormenet
Interesting link... thanks.
Marc Gravell
You're welcome :)
Stormenet
A: 
GvS
This isn't true, the build number can be anything you want and would probably change when actually doing releases. You can't rely on your build number to know when the compile happened.
Ray Booysen
Yes, the build number can be anything you want, but the default build number, the one that is generated using the "*" in the version is the number of days since 1/1/2000
GvS
I've made my answer more clear. I hope now there is no confusion between the user set build number and the generated default build number.
GvS
A: 

Do you looking for something like this:
(Get's the Date of Building the Assembly via Version-Info; Build-Number is days since 1.1.2000)

         var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
        DateTime versionsDatum = new DateTime(2000, 1, 1);
        versionsDatum = versionsDatum.AddDays(version.Build);
Alex