Search
Close this search box.

C#/.NET Little Wonders: Getting the Name of an Identifier

Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, but can help improve your code by making it easier to write and maintain. The index of all my past little wonders posts can be found here.

Visual Studio 2015 is on the horizon!  In fact, some of you may already have played with the preview and seen some of the many neat new things to come – both in the IDE and in the C# language.

For those who haven’t been keeping up with the announcements, allow me to take some blog time for the next few Little Wonders posts to talk about some of the neat new things that will be part of C# 6. 

Then, once it’s available for you to consume, you can hit the ground running with an arsenal of new little ways to make your code cleaner and more maintainable.

Why do we care about getting the name of a identifier?

Sometimes, we need to know the name of a variable, member, or type.  This may seem trivial, but there are many times where we end up needing this very thing, and thus we end up typing the name of a variable, member, or type as a string literal.

Take, for example, parameter validation.  When validating parameters, we will often check for their range, nullity, etc. and throw one of the various argument exceptions if the value isn’t what we expected.  In these exceptions, you’re expected to pass in the name of the identifier for the argument to let the caller know which argument was the problem.

For example, let’s say hypothetically that we don’t like the look of the expression !x.Contains(y) so we want to create a new extension method to make it read clearer, such as x.DoesNotContain(y). 

We could write an extension method such as:

// helper method to make not contain more visible than !Contains()
public static bool DoesNotContain<T>(this IEnumerable<T> collection, T value) {
  if (collection == null) {
    // first agument is the name of the argument
    throw new ArgumentNullException("collection");
  }

  return !collection.Contains(value);
}

This works quite well, but notice that “collection” is just a string and has no real tie to the actual argument name.  What happens if we refactor our code and change the variable name?  For example, most of the System.Linq extension methods use the parameter name source to represent the sequence being operated on, so let’s make our parameter name the same for consistency.

If we just renamed the variable, we might end up with this:

public static bool DoesNotContain<T>(this IEnumerable<T> source, T value)
{
    if (source == null)
    {
        // uh oh, this didn't get renamed with the variable!
        throw new ArgumentNullException("collection");
    }
 
    return !source.Contains(value);
}

I just used the IDE’s rename command to rename the parameter and all it’s usage.  Unfortunately, it didn’t realize that the string “collection” is also describing that parameter and so now, we have an exception that refers to a parameter that no longer exists which can cause confusion when the caller is told the parameter “collection” – which doesn’t exist – cannot be null.

The new nameof() operator

So how do we alleviate this pain?  Fortunately, C# 6 adds a new operator called nameof() operator whose job is to create a string representation of the name of a variable, member, or type at compile time.

Using this operator, the code now looks like this:

public static bool DoesNotContain<T>(this IEnumerable<T> source, T value)
{
    if (source == null)
    {
        // now, whenever source is renamed, we'll have the correct name
        throw new ArgumentNullException(nameof(source));
    }
 
    return !source.Contains(value);
}

Easy!

And, as I said, this happens at compile time – there is no runtime overhead or reflection involved.  Essentially, the code here boils down to the same thing as if we typed in the string literal – in fact that’s what it will actually compile into.  The difference is, the compiler now maintains that relationship and makes sure the string matches the name of the expression for us every time we build.

This isn’t only useful in exception handling, consider getting the function name for output:

// loads the dictionary from a file
private IEnumerable<string> LoadDictionary(string filename)
{
    // will output "Started LoadDictionary at ..."
    Console.WriteLine("Started " + nameof(LoadDictionary) + " at " + DateTime.Now);
 
    ...

Again, if the function name changes, your output will change accordingly. 

As another example, consider implementing INotifyPropertyChanged to notify observers when a property value changes.  Again, this requires you to give the name of the property as a string:

public int Total 
{
    get { return _total; }
    set 
    { 
        _total = value; 
 
        // determine the name of the Total property instead of hard-coded string
        PropertyChanged(this, new PropertyChangedEventArgs(nameof(Total)); 
    }
}

Or consider the times in frameworks like MVC where you often times hard-code strings to indicate certain identifiers in the code.

// this way, if the LogIn changes it's name, we will automatically change the link as well
<%= Html.ActionLink("Log in", @typeof(SignOnController), @nameof(SignOnController.LogIn))%>

These are just a few of the many examples where nameof() can be utilized to reduce the brittleness of your code in spots where it relies on a string being in sync with the name of an identifier. 

And, as stated before, it’s all compile-time magic so you get it essentially for free!

What nameof() does not do

The nameof() operator is very handy, but there’s a few things it won’t do.  For the most part, these are non-issues because having a name for some of these things wouldn’t make sense.  That said, it’s good to be aware of its limitations.

First of all, it only works on a subset of expressions that point to an identifier (i.e. a variable, member, or type name).  It will not work on other expressions that don’t evaluate to one of those things.

For instance, nameof(2 + 4) does not resolve to an identifier and thus is a compiler error.  Likewise, keywords such as if, while, for, etc. are not identifiers and thus nameof() any of these things is a compiler error as well.

Note that type aliases like int are actually considered keyword aliases to a type (e.g. int refers to System.Int32).  Thus, nameof(int) is a compiler error, but nameof(System.Int32) is not.

Compile-time pitfall

Like all things that are performed at compile time, you should take care to note that if your nameof() expression is evaluating a type or member identifier from another compilation unit (such as another assembly) it could become stale if the dependent library is updated by the referencing library is not rebuilt.  In reality, this is also a problem for other compile-time constants such as const values, enums, default parameter values, etc. 

Visual Studio is smart enough to compile the referencing assembly automatically when the dependency assembly changes, so this will not be an issue most of the time.  The only time you should run into this is if you manually copy just the dependency assembly without updating the referencing assembly.

Summary

The nameof() operator is a small addition to C# that adds up to real gains in maintainability.  Whenever you find yourself needing to create a string literal that matches an identifier in your code, consider using nameof() instead and let the compiler keep it in sync for you. 

Stay tuned for more Little Wonders of C# 6!

This article is part of the GWB Archives. Original Author: James Michael Hare

Related Posts