C# 6.0 has a lot of new features, one of them is nameof operator. Let's see how it's implemented internally and what we can do with it.
This operator will help us get rid of "magic strings" in our code. We all know following use case:
public void Method(int arg)
{
if (arg < 0)
{
throw new ArgumentOutOfRangeException("arg");
}
}
With nameof operator we can rewrite code in a nicer way:
public void Method(int arg)
{
if (arg < 0)
{
throw new ArgumentOutOfRangeException(nameof(arg));
}
}
That is! nameof just returns a string representation of variable\method\type\propery\field. This might be very helpful during refactoring, you do not need to worry about string literals in your code anymore :)
The same as String Interpolation and Null Propagation operator, nameof is just a syntax sugar. During compilation process, whole expression will be replaced by a string. Let's see following example:
static void Main(string[] args)
{
Console.WriteLine(nameof(args));
// Console output: args
}
And IL code:
IL_0001: ldstr "args"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
As we can see in line IL_0001, "args" is pushed on the stack with a ldsrt instruction.
Because it is a "compile-time operator" we cannot use expressions in the nameof operator. Following code will not compile because args.ToString() can be evaluated only in run-time:
Console.WriteLine(nameof(args.ToString().Length));
Here are more examples of nameof use:
namespace MyNameSpace
{
internal enum ETestEnum
{
FirstValue
}
internal class Program
{
private static string privateField;
public static string PublicProperty { get; set; }
static void Main(string[] args)
{
var localVar = 1;
// local variable
Console.WriteLine(nameof(localVar));
// field
Console.WriteLine(nameof(privateField));
// property
Console.WriteLine(nameof(PublicProperty));
// argument
Console.WriteLine(nameof(args));
// method
Console.WriteLine(nameof(Main));
// program
Console.WriteLine(nameof(Program));
// namespace
Console.WriteLine(nameof(MyNameSpace));
// generic type
Console.WriteLine(nameof(Action<Program, Program>));
//generic type's member
Console.WriteLine(nameof(Action<Program, Program>.Method));
// generic method
Console.WriteLine(nameof(GenericMethod));
// enum
Console.WriteLine(nameof(ETestEnum));
// enum's value
Console.WriteLine(nameof(ETestEnum.FirstValue));
}
private static void GenericMethod<T>()
{
}
}
}
Let's take a closer look at generic classes and methods. In case of Action<Program, Program> we will see only Action. The same with generic methods.
Also, if you want to get enum's value name you should use nameof operator instead of .ToString() method.
// preferable way
Console.WriteLine(nameof(ETestEnum.FirstValue));
// "old school" way
Console.WriteLine(ETestEnum.FirstValue.ToString());
If we look at IL code we will see why nameof is preferable in this case:
IL_004e: ldstr "FirstValue"
IL_0053: call void [mscorlib]System.Console::WriteLine(string)
IL_0058: nop
IL_0059: ldc.i4.0
IL_005a: stloc.0
IL_005b: ldloca.s V_0
IL_005d: constrained. MyNameSpace.ETestEnum
IL_0063: callvirt instance string [mscorlib]System.Object::ToString()
IL_0068: call void [mscorlib]System.Console::WriteLine(string)
As you can see, string constant (IL_004e) will be much more efficient than callvirt instruction (IL_0063).
Everyday use cases
INotifyPropertyChanged
public int Property
{
get { return this.p; }
set
{
this.p = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.p));
}
}
Parameters Validation
void Method(string arg)
{
if (arg == null)
{
throw new ArgumentNullException(nameof(arg));
}
}
XAML Dependency Property
public static DependencyProperty AddressProperty =
DependencyProperty.Register(
nameof(Address),
typeof(AddressType),
typeof(MainWindow));
Logging
void Method(int arg)
{
Log(nameof(Method), "Method Logged");
}
And much, much more...