14 Apr 2015
C# 6
Want to learn about other C# 6 features? Check out the full list of articles & source code on GitHub

nameof is a fantastic piece of syntactic sugar in C# 6, which aims to solve a major pain: magic strings. A magic string is a type of string in your application which is isn’t an input/output related but rather a marker or used for some comparison, for example you might do role checking with something that looks like this:

if (role == "admin")
{
}

The issue with this string “admin”, is that there is NO compiler checking for it. That means if you mistype the content of the string, you do not know it is wrong until the app fails. The second issue with a magic string, is that the refactoring tools do not commonly work with them, so if you changed “admin” to “administrator” in one place, there is no way to tools can find and update all the strings throughout you app and your app breaks again when it runs.

A lot of time you can clean this up with enumerators or objects. For example we can improve our role scenario but checking against an enumerator:

if (role == Roles.admin.ToString())
{
}

This no longer suffers from the two issues listed above Smile

Members & Magic Strings

The problem remains with magic strings which refer to members (fields, properties, methods, types etc…) of your code. In this first example we have a magic string pointing to the property Age:

public int Age
{
    get { return age; }
    set
    {
        age = value;
        RaisePropertyChanged("Age");
    }
}

For the second example we have a magic string  pointing to a class Track:

var type = Type.GetType("Track");

And finally our third example is around checking a field for null and raising an exception, if needed, with the correct field name:

private void RaisePropertyChanged(string propertyChanged)
{
    if (propertyChanged == null)
    {
        throw new ArgumentNullException("propertyChanged");
    }

    // do stuff
}

All of these examples suffer from the same two problems listed with magic strings, but until now, there hasn’t been a way to effectively clean them up.

nameof

The goal of the new nameof keyword is to solve this specific type of magic string, i.e. ones which refer to members in code. By using nameof we can change the above examples to the following:

// example 1
public int Age
{
    get { return age; }
    set
    {
        age = value;
        RaisePropertyChanged(nameof(Age));
    }
}

// example 2
var type = Type.GetType(nameof(Track));

// example 3
private void RaisePropertyChanged(string propertyChanged)
{
    if (propertyChanged == null)
    {
        throw new ArgumentNullException(nameof(propertyChanged));
    }

    // do stuff
}

Note we have eliminated the strings completely! This means if you mistype a member name at compile time you would get an error!

image

We also get FULL refactoring support now, since Visual Studio and other refactoring tools can get the information they need to identify that it is a member and replace/rename as needed.

More sugar

As mentioned at the start, this is just a case of syntactic sugar, the compiler is doing clever tricks for us and generating slightly different code. All nameof does, is instruct the compiler to convert the member to a string, so the outputted code is the same before with strings.

I want to recommend the TryRosyln website which is FANTASTIC to experiment with C# 6 and also shows you the decompiled code side by side, basically showing you how the syntactic sugar works:

image

What does it output?

In the first set of examples we looked at simple members, but what if we have something more complex for example a namespace or a class & property. In these cases it will output the last part each time:

nameof(Track.Band); // Class.Property - outputs: Property, in this case 'Band'
nameof(System.Configuration); // Namespace - outputs: Last namespace, in this case 'Configuration'
nameof(List); // List + Generics: outputs: The type of the object, in this case 'List' <
nameof(this.field); // this keyword + field - outputs the field name 'field'

What isn’t supported

nameof isn’t a solution to everything in .NET and there is a lot which won’t work. Here are some examples:

nameof(f()); // where f is a method - you could use nameof(f) instead
nameof(c._Age); // where c is a different class and _Age is private. Nameof can't break accessor rules.
nameof(List<>); // List<> isn't valid C# anyway, so this won't work
nameof(default(List<int>)); // default returns an instance, not a member
nameof(int); // int is a keyword, not a member- you could do nameof(Int32)
nameof(x[2]); // returns an instance using an indexer, so not a member
nameof("hello"); // a string isn't a member
nameof(1+2); // an int isn't a member

Is this a replacement for CallerMemberName?

I have written about a fantastic .NET 4.5 feature called CallerMemberName. To recap it is a way to attribute a parameter of a method and have the runtime change the value of that parameter to be the name of the calling member. In the following example the output will be ‘Main’, matching the name of the calling method:

private static void Main(string[] args)
{
    WhoCallsMe(); 
}

static void WhoCallsMe([CallerMemberName] string caller = "")
{
    Console.WriteLine(caller);
}
This seems to be similar to nameof but there are some fundamental differences, most importantly nameof is at COMPILE TIME and CallerMemberName is at RUNTIME. This means that this one method in the example can work with multiple callers; i.e. I could take the above example and have a different member call it and it will output the correct name of the caller. There is no way to do that with nameof, which is basically hard coded values. There is some overlap of functionality and in some cases, like XAML + RaisePropertyChanged where you could pick one or the other based on taste, but these two pieces of functionality do have their differences and there are times where CallerMemberName is the really only option.
Tags: 

Comments

Craig's picture

Unless this is something new in C# 6.0, I don't think List<track></track> is valid C#.

Thomas Levesque's picture

> List isn't valid C# anyway

Actually, there's one case where you can use List: typeof(List)

Juan Perez's picture

"The important thing to remember is that CallerMemberName is a compile time feature. So don't expect it to add any value to dynamic code. The same applies to CallerFilePath and CallerLineNumber." See http://simoncropp.com/callermembernameandruntimecode

Add new comment