Boxing/unboxing - treacherous conversion

Boxing/unboxing conversions are one of the most popular interview questions so I'm not going to explain them in this post(who wants to read another description anyway). Instead I will present one example, which will ensure you, that you understand "what is going on" completely. The example originates from a great book "CLR via C#" by Jeffrey Richter. If you haven't got a chance, I strongly recommend you to read it - it's a fantastic collection of many gotchas in C#/CLR.

Let's say we have following struct in our code:

public struct Point
{
        private int _x;
        private int _y;

        public Point(int x, int y)
        {
            _x = x;
            _y = y;
        }

        public void Change(int x, int y)
        {
            _x = x;
            _y = y;
        }

        public override string ToString()
        {
            return $"{_x},{_y}";
        }
}

(yes, I know that mutable structs are evil - it's not the case). Let's try to play with it and display something:

class Program
{
        static void Main(string[] args)
        {
            var point = new Point(1, 1);
            Console.WriteLine(point);

            point.Change(2, 2);
            Console.WriteLine(point);

            var o = (object)point;
            Console.WriteLine(o);

            ((Point)o).Change(3, 3);
            Console.WriteLine(o);

            Console.ReadLine();
        }
}

The question is - what do you expect a console will display?

1,1

2,2

2,2

3,3

This is what my first thought was like. This is what our intuition tells us. But hey, let's start this program:

1,1

2,2

2,2

2,2

This is something unexpected. How is it possible, that we are missing changing our point to (3, 3)?

The "problem" with this example for most people is, that they forget how unboxing is supposed to work. Casting o to Point doesn't mean, that we are changing its type. We are trying to represent a reference type stored on a managed heap as a value type, which needs to be pushed onto the local thread stack. To do that, compiler has to emit an additional variable, which will store contents of this conversion. Let's check MSIL for this operation:

IL_003a: ldloc.1      // o
IL_003b: unbox.any    Program.Point
IL_0040: stloc.2      // V_2
IL_0041: ldloca.s     V_2
IL_0043: ldc.i4.3     
IL_0044: ldc.i4.3     
IL_0045: call         instance void Program.Point::Change(int32, int32)
IL_004a: nop 

As you can see, compiler emited a V_2 variable, which is supposed to store unboxing result. Then this variable is loaded onto evaluation stack and Change() method is being invoked. Because we don't have any reference to it, we actually don't see, that we are trying to change a Point, that we never expected to be created. Just to make sure, we can check emitted code for writing a result:

IL_004b: ldloc.1      // o
IL_004c: call         void [mscorlib]System.Console::WriteLine(object)
IL_0051: nop   

If we compare it with local variables:

.locals init (
      [0] valuetype Program.Point point,
      [1] object o,
      [2] valuetype Program.Point V_2
 )

we can see, that Console.WriteLine() is being called for an o variable, thus Change() method is never called for it.

Summary

Boxing/unboxing conversion can be treacherous because of the all differences between value and reference types. Above example can be fixed if we use an interface, which declares Change() method - in such case no conversion will be needed. If you are interested in such "not-so-obvious" cases, I strongly recommend you to check ProblemBook.NET book, where you can find even more examples.

Making your application's version more descriptive with Stamp.Fody and TeamCity

Problem

Sometimes you want to display an application's version visible somewhere, so it is easy to determine, which version has been recently deployed. In .NET application the easiest way is to get a version number from the one of the following attributes:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

The problem is, that in the world of automatic builds and deployments, changing those values is cumbersome and error-prone. Of course you can shape your delivery process in a way, that will allow manual version changes - but we should avoid such actions if possible, shouldn't we?

Solution

Assuming that you use some kind of a build server, getting all necessary data(in my particular case - build number and SHA of a commit) can be pretty easy or very difficult. To be honest, it would be possible to create a whole functionality, I'm talking about, relying solely on TeamCity. The thing is, that the more your build server knows, the harder it gets to version it.

Because of all above concerns I decided to change the concept a little. The best idea I came up with was to get all necessary info directly from the .git folder of my solution after the build. Because I'd already had working psake build script, the easiest thing to do seemed to use some Powershell magic and fetch all what I needed using it. However, why should I extend my script when there is already a better solution?

Stamp.Fody

Yes, there is a weaver, which allows you to automate work needed to embed some Git info in application's version info. The best thing about it is, that it is completely transparent - all it needs is installed Fody in your solution.

Stamp's concept is pretty simple - it checks whether there is an AssemblyInformationalVersionAttribute attribute added to your assembly and if it is - it replaces predefined tokens used as a version's info using data found in your solution's .git folder:

[assembly: AssemblyInformationalVersion("%version%-%shorthash%-%branch%")]

In the above example it is possible to get following result - 1.0.0.0-0772a13a-develop. More tokens are listed on the weaver's GitHub page.

We have some Git info in application's version - what about getting a build number and combining all those values?

TeamCity & psake

As I mentioned before, I use a psake script to handle all build-related tasks. This lets me version all steps required during building an application. Because Stamp takes care of getting the Git info, the only thing left is to combine it somehow with a build number provided by TeamCity.

The very first thing needed here is to pass a build number parameter to a psake script. To do that, you have to go to the build steps of your project and find the one, which executes psake. There, in the script source area, you probably have something similar to:

Import-Module .\.tools\psake.4.4.2\tools\psake.psm1
Invoke-Psake .\build.ps1

All you need is to add a parameter using -parameters switch:

Import-Module .\.tools\psake.4.4.2\tools\psake.psm1
Invoke-Psake .\build.ps1 -parameters @{tcBuildNumer=%build.number%}

Now each build will pass its number to our script. Next todo is to create a function in Powershell, which will obtain generated application's version from an assembly:

function Assembly-GetVersion($file) {    
    $version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($file).ProductVersion;
    return $version;
}

The last thing is to use above function and generate a new application's version number, which will be much more informative:

Task ExtractVersion {
    $assemblyVersion = Assembly-GetVersion "path_to_your_assembly"
    $majorVersion, $minorVersion, $buildNumber, $revision = $assemblyVersion.split('.', 4)
    $version = "$majorVersion.$minorVersion.$tcBuildNumber.$revision"
    
    New-Item "path_to_the_base_directory\version.json" -type file -value "{`"Version`": `"$version`"}"
}

Note that above syntax is correct using Powershell 4.0 - if you have a different version, some changes would be required. What is more - I am generating a version.json file, which can be requested by your front-end and displayed(e.g. using Angular):

var version = $http.get('version.json');
version.success(function (res) {
     $scope.appVersion = res.Version;
});

Summary

By using mentioned tools you can easily generate an application's version, which will easily tell you and your client what version has been deployed. It can be especially helpful when dealing with multiple environments + automatic deployments(e.g. using Octopus Deploy) during development phase - it is easy to determine whether correct version of an application is being tested and used.