What is the purpose of nameof?
Asked Answered
L

17

373

Version 6.0 got a new feature of nameof, but I can't understand the purpose of it, as it just takes the variable name and changes it to a string on compilation.

I thought it might have some purpose when using <T> but when I try to nameof(T) it just prints me a T instead of the used type.

Any idea on the purpose?

Lindblad answered 29/7, 2015 at 9:4 Comment(5)
See also msdn.microsoft.com/library/dn986596.aspxReste
There wasn't a way to get that T before. There was a way to get the used type before.Homans
Definitely useful when refactory/renaming the name within nameof. Also helps to prevent typos.Morass
nameof comes in handy with nunit 3 TestCaseData. The docs show a method name by string [Test, TestCaseSource(typeof(MyDataClass), "TestCases")], which can be replaced with [Test, TestCaseSource(typeof(MyDataClass), nameof(MyDataClass.TestCases))]. Much nicer.Bak
The official documentation of nameof has moved to here: learn.microsoft.com/en-us/dotnet/csharp/language-reference/… - It also lists key use cases which serve as a pretty good answer to the question.Daff
T
428

What about cases where you want to reuse the name of a property, for example when throwing exception based on a property name, or handling a PropertyChanged event. There are numerous cases where you would want to have the name of the property.

Take this example:

switch (e.PropertyName)
{
    case nameof(SomeProperty):
    { break; }

    // opposed to
    case "SomeOtherProperty":
    { break; }
}

In the first case, renaming SomeProperty will cause a compilation error if you don't change both the property definition and the nameof(SomeProperty) expression. In the second case, renaming SomeOtherProperty or altering the "SomeOtherProperty" string will result in silently broken runtime behavior, with no error or warning at build time.

This is a very useful way to keep your code compiling and bug free (sort-of).

(A very nice article from Eric Lippert why infoof didn't make it, while nameof did)

Tiller answered 29/7, 2015 at 9:7 Comment(12)
I understand the point, just adding that resharper changes the strings when refactoring names, not sure if VS has similar functionality.Consequential
It has. But both Resharper and VS don't work over projects for example. This does. In fact, this is the better solution.Tiller
Another common use case is routing in MVC using nameof and the action's name instead of a hard-coded string.Vibrato
@RJCuthbertson Very logical but what about using nameof on views for action name? Controller class isn't static so that we cannot get the action name, any simple solution for this too??Huai
@sotn I'm not sure I understand what you're asking. There's nothing stopping you from using it like public class MyController { public ActionResult Index() { return View(nameof(Index)); } } - and you can use nameof on non-static members (for instance you can call nameof(MyController.Index) using the class above and it will emit "Index"). Check out the examples at msdn.microsoft.com/en-us/library/…Vibrato
@RJCuthbertson wow accessing non-static method name without an instance?? that's some hardcore compiler logic lolHuai
I don't see why that is special. Variable names are always the same, right? Whether you have an instance or not, the variable names won't change @sotnTiller
@PatrickHofman Variable names maybe but what about method names? You can use nameof with method names too. Assume that I have an Action in MVC application named Index and I want to change it's name because I want my users to access the site as '/MyController/Home/' and also don't want to do it by using a Route Attribute and just rename it as "Home". Searching for "Index" and replacing it with "Home" in whole project can take lots of time..Huai
@PatrickHofman And I'm not sure I understand what you described. But if you meant what's so special about using nameof on non-static method names? Well, in a cshtml file for example; we don't have access to Controller instance and we use lots of urls etc. by using UrlHelpers like Url.Action("Index") etc. Therefore, it means that we can use Url.Action(nameof(HomeController.Index)). And when we rename it in the future and turn the view compilation on, we can rename the action names easily.. Using it without an instance is big imo..Huai
Not if you understand this is all done on compile time. There aren't instances at that time yet, just code @sotnTiller
@PatrickHofman lol of course it is. nameof has no effect on the generated IL etc. But, I think that it is a nice little thing that can ease your job a little..Huai
In case anyone's wondering what happens if SomeProperty gets renamed SomeOtherProperty, you get a compilation error: learn.microsoft.com/en-us/dotnet/csharp/misc/cs0152Taxation
R
226

It's really useful for ArgumentException and its derivatives:

public string DoSomething(string input) 
{
    if(input == null) 
    {
        throw new ArgumentNullException(nameof(input));
    }
    ...

Now if someone refactors the name of the input parameter the exception will be kept up to date too.

It is also useful in some places where previously reflection had to be used to get the names of properties or parameters.

In your example nameof(T) gets the name of the type parameter - this can be useful too:

throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method.");

Another use of nameof is for enums - usually if you want the string name of an enum you use .ToString():

enum MyEnum { ... FooBar = 7 ... }

Console.WriteLine(MyEnum.FooBar.ToString());

> "FooBar"

This is actually relatively slow as .Net holds the enum value (i.e. 7) and finds the name at run time.

Instead use nameof:

Console.WriteLine(nameof(MyEnum.FooBar))

> "FooBar"

Now .Net replaces the enum name with a string at compile time.


Yet another use is for things like INotifyPropertyChanged and logging - in both cases you want the name of the member that you're calling to be passed to another method:

// Property with notify of change
public int Foo
{
    get { return this.foo; }
    set
    {
        this.foo = value;
        PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.Foo));
    }
}

Or...

// Write a log, audit or trace for the method called
void DoSomething(... params ...)
{
    Log(nameof(DoSomething), "Message....");
}
Repugnance answered 29/7, 2015 at 9:7 Comment(8)
And you've put another cool feature in: string interpolation!Tiller
@PatrickHofman and typeof(T), which is another piece of compile-time sugar that's useful in similar circumstances :-)Repugnance
One thing that i'm missing is something like nameofthismethod. You can use Log.Error($"Error in {nameof(DoSomething)}...") but if you copy-paste this to other methods you won't notice that it's still referring to DoSomething. So while it's working perfectly with local variables or parameters the method-name is a problem.Einsteinium
Do you know if nameOf will use the [DisplayName] attribute if present? For the enum example I use [DisplayName] often with MVC projectsDotson
@Repugnance What did you find out? There's also the [Description] attribute. It would be nice to give args to the nameOf, for eg deciding to return the type FullName instead of Name when using nameOf(System.String)Dotson
@LukeTO'Brien ah, no, I thought you were saying that it did. I think nameof always gets the actual name, ignoring any attributes.Repugnance
Unfortunately a developer tried to follow the first ArgumentException pattern but generalized to all exceptions, so all my catch blocks are sprinkled with throw new Exception(nameof(ex)) which hides the actual exception and just logs "ex". The answer has good examples, but make sure you understand them before you try to apply them.Columbian
@Columbian Yes, it's fairly specialised and not something that you would use often. However that throw new is a whole other anti-pattern - I find over-using catch to be a common problem with junior devs because it feels like fixing the problem (when most of the time it's just hiding it).Repugnance
P
38

Another use-case where nameof feature of C# 6.0 becomes handy - Consider a library like Dapper which makes DB retrievals much easier. Albeit this is a great library, you need to hardcode property/field names within query. What this means is that if you decide to rename your property/field, there are high chances that you will forget to update query to use new field names. With string interpolation and nameof features, code becomes much easier to maintain and typesafe.

From the example given in link

without nameof

var dog = connection.Query<Dog>(
    "select Age = @Age, Id = @Id",
    new {Age = (int?) null, Id = guid});

with nameof

var dog = connection.Query<Dog>(
    $"select {nameof(Dog.Age)} = @Age, {nameof(Dog.Id)} = @Id",
    new {Age = (int?) null, Id = guid});
Persona answered 16/11, 2016 at 1:57 Comment(2)
I love Dapper and I really like string interporlations, but IMO this looks so ugly. The risk of breaking a query by renaming a column seems so small compared to such ugly queries. At first sight I'd say I prefer writing EF LINQ queries, or following a convention like [TableName].[ColumnName] where I can easily find/replace my queries when I need.Barn
@Barn I use Dapper FluentMap to prevent such queries (and also for separation of concerns)Ferdy
R
30

Your question already expresses the purpose. You must see this might be useful for logging or throwing exceptions.

For example:

public void DoStuff(object input)
{
    if (input == null)
    {
        throw new ArgumentNullException(nameof(input));
    }
}

This is good. If I change the name of the variable, the code will break instead of returning an exception with an incorrect message.


Of course, the uses are not limited to this simple situation. You can use nameof whenever it would be useful to code the name of a variable or property.

The uses are manifold when you consider various binding and reflection situations. It's an excellent way to bring what were run time errors to compile time.

Rapscallion answered 29/7, 2015 at 9:7 Comment(6)
for logging i could just write the name of the variable myself, would be shorterLindblad
@atikot: But then, if you rename the variable, the compiler won't notice that the string doesn't match any more.Voltz
I actually use resharper which takes it to account, but i see your point.Lindblad
@atikot, so do I, but Resharper only generates a warning, not a compiler error. There's a difference between a certainty and good advice.Rapscallion
@atikot, and, Resharper doesn't check logging messagesRapscallion
@Jodrell: And, I suspect, it doesn't check various other uses, either - how about WPF bindings created in code-behind, custom OnPropertyChanged methods (that directly accept property names rather than PropertyChangedEventArgs), or calls to reflection to look for a particular member or type?Voltz
C
14

The most common use case I can think of is when working with the INotifyPropertyChanged interface. (Basically everything related to WPF and bindings uses this interface)

Take a look at this example:

public class Model : INotifyPropertyChanged
{
    // From the INotifyPropertyChanged interface
    public event PropertyChangedEventHandler PropertyChanged;

    private string foo;
    public String Foo
    {
        get { return this.foo; }
        set
        {
            this.foo = value;
            // Old code:
            PropertyChanged(this, new PropertyChangedEventArgs("Foo"));

            // New Code:
            PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));           
        }
    }
}

As you can see in the old way we have to pass a string to indicate which property has changed. With nameof we can use the name of the property directly. This might not seem like a big deal. But image what happens when somebody changes the name of the property Foo. When using a string the binding will stop working, but the compiler will not warn you. When using nameof you get a compiler error that there is no property/argument with the name Foo.

Note that some frameworks use some reflection magic to get the name of the property, but now we have nameof this is no longer neccesary.

Cutty answered 29/7, 2015 at 19:3 Comment(4)
Whilst this is a valid approach, a more convenient (and DRY) approach is to use the [CallerMemberName] attribute on a new method's param to raise this event.Throw
I agree CallerMemberName is also nice, but its a separate use case, since (as you said) you can only use it in methods. As for DRY, I'm not sure if [CallerMemberName]string x = null is better than nameof(Property). You could say the property name is used twice, but thats basically the argument passed to a function. Not really what is meant with DRY I think :).Cutty
Actually you can use it in properties. They are members too. The benefit over nameof is that the property setter needn't specify the property name at all, eliminating the possibility of copy/paste bugs.Throw
It's a 'better together' situation for INotifyPropertyChanged, using the [CallerMemberNameAttribute] allows the change notification to be cleanly raised from a property setter, while the nameof syntax allows a change notification to be cleanly raised from a different location in your code.Washbasin
T
12

Most common usage will be in input validation, such as

//Currently
void Foo(string par) {
   if (par == null) throw new ArgumentNullException("par");
}

//C# 6 nameof
void Foo(string par) {
   if (par == null) throw new ArgumentNullException(nameof(par));
}

In first case, if you refactor the method changing par parameter's name, you'll probably forget to change that in the ArgumentNullException. With nameof you don't have to worry about that.

See also: nameof (C# and Visual Basic Reference)

Tattoo answered 29/7, 2015 at 9:9 Comment(1)
why I don't have to worry about that?Outwork
M
9

Let's say you need to print the name of a variable in your code. If you write:

int myVar = 10;
print("myVar" + " value is " + myVar.toString());

and then if someone refactors the code and uses another name for myVar, he/she would have to look for the string value in your code and change it accordingly.

Instead, if you write:

print(nameof(myVar) + " value is " + myVar.toString());

It would help to refactor automatically!

Misfile answered 29/7, 2015 at 9:12 Comment(1)
I wish there had been a special variable-parameter syntax which would pass an array of tuples, one for each parameter, containing the source code representation, the Type, and the value. That would make it possible for code invoking logging methods to eliminate a lot of redundancy.Einstein
N
9

The ASP.NET Core MVC project uses nameof in the AccountController.cs and ManageController.cs with the RedirectToAction method to reference an action in the controller.

Example:

return RedirectToAction(nameof(HomeController.Index), "Home");

This translates to:

return RedirectToAction("Index", "Home");

and takes takes the user to the 'Index' action in the 'Home' controller, i.e. /Home/Index.

Noeminoesis answered 22/4, 2016 at 13:55 Comment(2)
Why not go whole-hog and use return RedirectToAction(nameof(HomeController.Index), nameof(HomeController).Substring(nameof(HomeController),0,nameof(HomeController).Length-"Controller".Length)); ?Schaub
@Schaub because one of those things is done in compilation and the other isn't? :)Longlived
A
8

The MSDN article lists MVC routing (the example that really clicked the concept for me) among several others. The (formatted) description paragraph reads:

  • When reporting errors in code,
  • hooking up model-view-controller (MVC) links,
  • firing property changed events, etc.,

you often want to capture the string name of a method. Using nameof helps keep your code valid when renaming definitions.

Before you had to use string literals to refer to definitions, which is brittle when renaming code elements because tools do not know to check these string literals.

The accepted / top rated answers already give several excellent concrete examples.

Apure answered 5/8, 2015 at 16:16 Comment(0)
L
6

As others have already pointed out, the nameof operator does insert the name that the element was given in the sourcecode.

I would like to add that this is a really good idea in terms of refactoring since it makes this string refactoring safe. Previously, I used a static method which utilized reflection for the same purpose, but that has a runtime performance impact. The nameof operator has no runtime performance impact; it does its work at compile time. If you take a look at the MSIL code you will find the string embedded. See the following method and its disassembled code.

static void Main(string[] args)
{
    Console.WriteLine(nameof(args));
    Console.WriteLine("regular text");
}

// striped nops from the listing
IL_0001 ldstr args
IL_0006 call System.Void System.Console::WriteLine(System.String)
IL_000C ldstr regular text
IL_0011 call System.Void System.Console::WriteLine(System.String)
IL_0017 ret

However, that can be a drawback if you plan to obfuscate your software. After obfuscation the embedded string may no longer match the name of the element. Mechanisms that rely on this text will break. Examples for that, including but not limited to are: Reflection, NotifyPropertyChanged ...

Determining the name during runtime costs some performance, but is safe for obfuscation. If obfuscation is neither required nor planned, I would recommend using the nameof operator.

Leatrice answered 1/8, 2015 at 12:36 Comment(0)
S
3

The purpose of the nameof operator is to provide the source name of the artifacts.

Usually the source name is the same name as the metadata name:

public void M(string p)
{
    if (p == null)
    {
        throw new ArgumentNullException(nameof(p));
    }
    ...
}

public int P
{
    get
    {
        return p;
    }
    set
    {
        p = value;
        NotifyPropertyChanged(nameof(P));
    }
}

But this may not always be the case:

using i = System.Int32;
...
Console.WriteLine(nameof(i)); // prints "i"

Or:

public static string Extension<T>(this T t)
{
    return nameof(T); returns "T"
}

One use I've been giving to it is for naming resources:

[Display(
    ResourceType = typeof(Resources),
    Name = nameof(Resources.Title_Name),
    ShortName = nameof(Resources.Title_ShortName),
    Description = nameof(Resources.Title_Description),
    Prompt = nameof(Resources.Title_Prompt))]

The fact is that, in this case, I didn't even need the generated properties to access the resources, but now I have a compile time check that the resources exist.

Satchel answered 31/7, 2015 at 0:6 Comment(0)
S
3

The purpose of nameof is refactoring. For example when you change the name of a class to which you refer to through nameof somewhere else in your code you will get a compilation error which is what you want. If you didn't use nameof and had just a plain string as a reference you'd have to fulltext search for the name of the class in order to change it. That's a pain in the bottom. With nameof you can rest easy, build, and get all the cases for change automatically in your IDE.

Singleton answered 2/9, 2021 at 7:48 Comment(0)
W
1

Another use case of nameof is to check tab pages, instead of checking the index you can check the Name property of the tabpages as follow:

if(tabControl.SelectedTab.Name == nameof(tabSettings))
{
    // Do something
}

Less messy :)

Wolter answered 1/4, 2019 at 8:20 Comment(0)
P
1

I find that nameof increases the readability of very long and complex SQL statements in my applications. It makes the variables stand out of that sea of strings and eliminates your job of figuring out where the variables are used in your SQL statements.

public bool IsFooAFoo(string foo, string bar)
{
    var aVeryLongAndComplexQuery = $@"SELECT yada, yada
    -- long query in here
    WHERE fooColumn = @{nameof(foo)}
    AND barColumn = @{nameof(bar)}
    -- long query here";


    SqlParameter[] parameters = {
        new SqlParameter(nameof(foo), SqlDBType.VarChar, 10){ Value = foo },
        new SqlParameter(nameof(bar), SqlDBType.VarChar, 10){ Value = bar },
    }
}
Purusha answered 16/1, 2020 at 17:21 Comment(0)
E
0

One of the usage of nameof keyword is for setting Binding in wpf programmatically.

to set Binding you have to set Path with string, and with nameof keyword, it's possible to use Refactor option.

For example, if you have IsEnable dependency property in your UserControl and you want to bind it to IsEnable of some CheckBox in your UserControl, you can use these two codes:

CheckBox chk = new CheckBox();
Binding bnd = new Binding ("IsEnable") { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);

and

CheckBox chk = new CheckBox();
Binding bnd = new Binding (nameof (IsEnable)) { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);

It's obvious the first code can't refactor but the secend one...

Eckhart answered 17/7, 2016 at 23:58 Comment(0)
U
0

Previously we were using something like that:

// Some form.
SetFieldReadOnly( () => Entity.UserName );
...
// Base form.
private void SetFieldReadOnly(Expression<Func<object>> property)
{
    var propName = GetPropNameFromExpr(property);
    SetFieldsReadOnly(propName);
}

private void SetFieldReadOnly(string propertyName)
{
    ...
}

Reason - compile time safety. No one can silently rename property and break code logic. Now we can use nameof().

Unsheathe answered 26/7, 2016 at 22:9 Comment(0)
R
0

It has advantage when you use ASP.Net MVC. When you use HTML helper to build some control in view it uses property names in name attribure of html input:

@Html.TextBoxFor(m => m.CanBeRenamed)

It makes something like that:

<input type="text" name="CanBeRenamed" />

So now, if you need to validate your property in Validate method you can do this:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
  if (IsNotValid(CanBeRenamed)) {
    yield return new ValidationResult(
      $"Property {nameof(CanBeRenamed)} is not valid",
      new [] { $"{nameof(CanBeRenamed)}" })
  }
}

In case if you rename you property using refactoring tools, your validation will not be broken.

Ressieressler answered 20/3, 2018 at 13:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.