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?
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 change the name of the property too, or it will break compilation. The last case doesn't.
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)
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....");
}
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 });
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 or 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. Its an excellent way to bring what were run time errors to compile time.
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.
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)
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
.
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.
Consider that you use a variable in your code and need to get the name of the variable and lets say print it, you should have to use
int myVar = 10;
print("myVar" + " value is " + myVar.toString());
And if then someone refactors the code and uses another name for "myVar", he/she would have to watch for the string value in your code and chenge it accordingly.
Instead if you had
print(nameof(myVar) + " value is " + myVar.toString());
It would help to refactor automatically!
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.
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.
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...
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().
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.
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 :)
来源:https://stackoverflow.com/questions/31695900/what-is-the-purpose-of-nameof