Use Compile Time Info In C# 5.0 Code

I just stumbled upon a great new feature of C# 5.0 reading  Charles Petzold’s 6th edition of “Programming Windows” (a lot of water gone under the bridge since the 2nd edition, Borland C and I were inseperable!).

One might say “at long last”, but with C# 5.0 you’re now able to include compiler info in your program: Line number, Source file and last – but not least – the method/property name. Apart from logging, the property name being very useful when using the MVVM pattern with XAML.

The so called “Caller Info Attributes” take the shape of annotations, and here is a very small sample program that illustrates these three new annotations:

using System;
using System.Runtime.CompilerServices;

namespace CallerInfoAttributes
{
    class Program
    {
        public static int _myproperty;
        public static int MyProperty
        {
            get
            {
                Log("Get " + _myproperty.ToString());
                return _myproperty;
            }
            set
            {
                Log("Set " + value.ToString());
                _myproperty = value;
            }
        }

        static void Main(string[] args)
        {
            Log("Hello");
            MyProperty = 8;
            MyProperty = MyProperty * 3;

            Console.ReadLine();
        }

        static void Log(string message,
                       [CallerMemberName] string member = "",
                       [CallerFilePath] string file = "",
                       [CallerLineNumber] int line = 0)
        {
            var s = String.Format("{1} ({2}:{3}) - {0}", message, member, file, line);
            Console.WriteLine(s);
        }
    }
}

The output, completely as expected:

image

Checking the generated code in dotNetSpy shows that the compiler actually inserts the compile time strings into the call, making for very good performance especially compared to the previous Expression Tree hacks sometimes used with MVVM:

// Type: CallerInfoAttributes.Program
// Assembly: CallerInfoAttributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// Assembly location: E:\Projects\CallerInfoAttributes\CallerInfoAttributes\bin\Debug\CallerInfoAttributes.exe

using System;
using System.Runtime.CompilerServices;

namespace CallerInfoAttributes
{
  internal class Program
  {
    public static int _myproperty;

    public static int MyProperty
    {
      get
      {
        Program.Log("Get " + Program._myproperty.ToString(), "MyProperty", "e:\\Projects\\CallerInfoAttributes\\CallerInfoAttributes\\Program.cs", 13);
        return Program._myproperty;
      }
      set
      {
        Program.Log("Set " + value.ToString(), "MyProperty", "e:\\Projects\\CallerInfoAttributes\\CallerInfoAttributes\\Program.cs", 18);
        Program._myproperty = value;
      }
    }

    private static void Main(string[] args)
    {
      Program.Log("Hello", "Main", "e:\\Projects\\CallerInfoAttributes\\CallerInfoAttributes\\Program.cs", 25);
      Program.MyProperty = 8;
      Program.MyProperty *= 3;
      Console.ReadLine();
    }

    private static void Log(string message, [CallerMemberName] string member = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
    {
      Console.WriteLine(string.Format("{1} ({2}:{3}) - {0}", (object) message, (object) member, (object) file, (object) line));
    }
  }
}

Read more about this small, but important improvement at http://msdn.microsoft.com/en-us/library/hh534540(v=vs.110).aspx

Advertisements
Posted in C#

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s