So, nameof(MyClass) returns the string "MyClass". And on first glance that's pretty useless, because if you have to type the name of the thing, why not type two quotes instead of the more unwieldy nameof?
The key is playing nice with IDEs! If you're referring to the name of a thing, that thing might get renamed, or you might want to find references to that thing. You surely don't want to misspell the thing! Your LSP typically helps you achieve all these worthy goals, but the LSP can't see inside your string. What it sees are any references you make inside the nameof operator!
If you use nameof, when you rename your class, the name of the class you printed will get updated instead of being hardcoded. And what's even cooler is that you can refer to things in scope, like variables in the current function or fields in the current class, and references will work as expected! You can even refer to some other class' field like MyOtherClass.someField and this will evaluate to the string "someField" and count as a reference for that field for the purposes of refactors!
For example, in my game I have mappings from my GameDb to C# structs written by hand (why didn't automate it? because there hasn't been a need to), and while I've been careful in my typing and disciplined in my renaming (so it never caused trouble), today I realized I could change all the lines that look like this:
Code: Select all
id: row.GetString("id"),
Code: Select all
id: row.GetString(nameof(id)),
Code: Select all
public static object FromRow(CsvRow row) {
return New(
id: row.GetString(nameof(id)),
name: row.GetString(nameof(name)),
description: row.GetString(nameof(description)),
distance: row.GetFloat(nameof(distance)),
spriteOffset: row.GetFloat(nameof(spriteOffset)),
comboTree: row.GetString(nameof(comboTree)),
sprite: row.GetAsset<Texture>(nameof(sprite)),
attackPower: row.GetFloat(nameof(attackPower)),
attackSpeed: row.GetFloat(nameof(attackSpeed)),
speedBetweenCombos: row.GetFloat(nameof(speedBetweenCombos)),
burnChance: row.GetFloat(nameof(burnChance)),
bleedChance: row.GetFloat(nameof(bleedChance)),
loadoutSlotTweaks: row.GetConEgg<LoadoutSlotTweaks>(nameof(loadoutSlotTweaks))
);
}
Now I still need to adjust the names of the CSV columns if I ever rename one of these struct fields, so this does not give me 100% painless refactors, but it takes care of one more thing. It's a tiny improvement, but a substantial one!
A side effect (or perhaps, the main point!) of nameof is also that you can't misspell a field name. No "bledChance" will slip into your game causing runtime errors. It's an all-around great feature and I can't think of a good reason it shouldn't be on every language.
Some people would compare this to Rust's stringify! macro, but while they're related that's not the same feature at all. Unless I'm mistaken, stringify! works at the token level, so it will not save you from any typos and won't participate in "find all references" or renaname refactors from the LSP. The use case for stringify is authoring macros, which is a completely different (but useful!) thing.