Magic Strings: How to avoid them in C#

 

One of my least favourite things about the .NET Framework is that there are plenty of places where it expects you use magic strings . These make maintaining your application harder as refactoring through Visual Studio will not pick up these references, which then get left behind with their original value. This blog post is to mostly share a very useful code snippet with you that helps us to avoid using magic strings and instead uses lambda expressions to specify the name we want.

Avoiding magic strings by using expression trees

I actually found this image when Googling for “magic string .net”, so perfect for this blog post.

What are magic strings?

Magic strings are where you have taken something like a class/method/variable name and written it within a string, which is then used to identify the appropriate class/method/variable, for example;

public void myMethod(string myParameter)
{
    if (myParameter == null)
    {
        throw new ArgumentNullException("myParameter");
    }
}

As you can see the method has a parameter which we check to see whether or not it is null, if it is null we are throwing an ArgumentNullException, which allows you to specify the parameter name but only allows you to specify it as a hard coded string. As I mentioned in the introduction the problem comes when we start looking to do things like refactoring where we rename the parameter but because we have also specified the parameter name as a string this isn’t picked up, it doesn’t cause a compilation error, it can just get left there, which isn’t what we want. There are tools like Resharper which will also search comments for references to the name but it is better to avoid this problem than to use tools to deal with the problem afterwards.

The magic anti-magic strings code

So I am currently looking at implementing a Ribbon for the XML File Explorer and found a good explanation on how to do it here, but while I was looking through some of the other things Arik has done I found this little beauty. The code uses Expressions allowing us to specify a variable, field, method, property and retrieve the name as a string, it also includes just for completeness a way of getting a class name as string although this is done in a different way. The website provides a sample project which contains the code, although strangely enough you download it as a zip.txt.

using System;
using System.Linq.Expressions;

namespace Utils
{
    public static class @string
    {
        private static string GetMemberName(Expression expression)
        {
            switch (expression.NodeType)
            {
                case ExpressionType.MemberAccess:
                    var memberExpression = (MemberExpression)expression;
                    var supername = GetMemberName(memberExpression.Expression);

                    if (String.IsNullOrEmpty(supername))
                        return memberExpression.Member.Name;

                    return String.Concat(supername, '.', memberExpression.Member.Name);

                case ExpressionType.Call:
                    var callExpression = (MethodCallExpression)expression;
                    return callExpression.Method.Name;

                case ExpressionType.Convert:
                    var unaryExpression = (UnaryExpression)expression;
                    return GetMemberName(unaryExpression.Operand);

                case ExpressionType.Constant:
                case ExpressionType.Parameter:
                    return String.Empty;

                default:
                    throw new ArgumentException("The expression is not a member access or method call expression");
            }
        }

        public static string of<T>(Expression<Func<T>> expression)
        {
            return GetMemberName(expression.Body);
        }

        public static string of(Expression<Action> expression)
        {
            return GetMemberName(expression.Body);
        }

        public static string of<T>()
        {
            return typeof(T).Name;
        }
    }
}

This now allows for our earlier example to stop using magic strings and instead just pass in the variable name like so;

public void myMethod(string myParameter)
{
    if (myParameter == null)
    {
        throw new ArgumentNullException(@string.of(() => myParameter));
    }
}

Which if we refactor the parameter to myNewParameter, gives us this;

public void myMethod(string myNewParameter)
{
    if (myNewParameter == null)
    {
        throw new ArgumentNullException(@string.of(() => myNewParameter));
    }
}

Which I’m sure you’ll agree is much better than when we would refactor and then have to ensure that we haven’t hard coded the name as a string somewhere