Logging properties–an easier way


I have often wanted a nice, easy way to simplify the writing and maintenance of code like this:

 

Log.Trace(string.Format(“FooSetting.BarProperty1 = {0}”), FooSetting.BarProperty1));

Log.Trace(string.Format(“FooSetting.BarProperty2 = {0}”), FooSetting.BarProperty2));

Log.Trace(string.Format(“FooSetting.BazLongerProperty= {0}”), FooSetting.BazLongerProperty));

…for the writing and maintenance of such code is ever filled with tedious mouse clicking, copy and pasting, typo correction in duplicate, manual refactoring of string constants, blah blah ugh.

Turns out that since the introduction of LINQ expressions into C#, there are some major nice-ifications to such code available.

(I’m pretty sure I’m reinventing this, I don’t mind not being the first, just as long I’m helping popularize the practice.)

namespace LogProperty

{
    using System.Linq.Expressions; 

    class Program

    {

        public int Prop { get; set; }

 

        static void LogProperty<TResult>(Expression<Func<TResult>> expr)

        {

            Debug.Assert(expr.NodeType == ExpressionType.Lambda);

            Debug.Assert(expr.Body.NodeType == ExpressionType.MemberAccess);

            string name = ((MemberExpression)expr.Body).Member.Name;

            Console.WriteLine(name + ” = “ + expr.Compile().Invoke());

        }

 

        static void Main(string[] args)

        {

            Program p = new Program();

            LogProperty(() => p.Prop);

            LogProperty(() => new Program { Prop = 3 }.Prop);

        }

    }

}

Ta da! Refactorable logging!

image

Comments (4)

  1. Naren says:

    Thanks. I tried using the code.

    Getting error:

    the type or namespace name 'Expression' could not be found (are you missing a using directive or an assembly reference?)

    at the line

    static void LogProperty<TResult>(Expression<Func<TResult>> expr)

    Any suggestion?

  2. tilovell09 says:

    using System.Linq.Expressions;

  3. John "Z-Bo" Zabroski says:

    Note, this blog entry is somewhat obsolete only 2 months after posting, as .NET 4.5 introduced CallerMemberName: msdn.microsoft.com/…/system.runtime.compilerservices.callermembernameattribute.aspx

  4. tilovell09 says:

    @John – cool! Didn't know about that one.