6.0版获得了nameof的新功能,但我不能理解它的目的,因为它只是接受变量名并在编译时将其更改为字符串。
我认为它在使用<T>时可能有一些目的,但当我尝试命名(T)时,它只是打印我一个T而不是使用的类型。
知道目的吗?
6.0版获得了nameof的新功能,但我不能理解它的目的,因为它只是接受变量名并在编译时将其更改为字符串。
我认为它在使用<T>时可能有一些目的,但当我尝试命名(T)时,它只是打印我一个T而不是使用的类型。
知道目的吗?
当前回答
假设您需要在代码中打印一个变量的名称。如果你这样写:
int myVar = 10;
print("myVar" + " value is " + myVar.toString());
然后如果有人重构代码并使用另一个名称myVar,他/她将不得不在你的代码中寻找字符串值并相应地更改它。
相反,如果你这样写:
print(nameof(myVar) + " value is " + myVar.toString());
这将有助于自动重构!
其他回答
我发现nameof增加了应用程序中非常长和复杂的SQL语句的可读性。它使变量从字符串的海洋中脱颖而出,并消除了确定变量在SQL语句中的使用位置的工作。
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 },
}
}
最常见的用法是在输入验证中,例如
//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));
}
在第一种情况下,如果你重构了改变par参数名称的方法,你可能会忘记在ArgumentNullException中改变它。有了nameof你就不用担心了。
参见:nameof (c#和Visual Basic参考)
我能想到的最常见的用例是使用INotifyPropertyChanged接口时。(基本上所有与WPF和绑定相关的东西都使用这个接口)
看看这个例子:
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)));
}
}
}
正如您可以看到的,在旧的方法中,我们必须传递一个字符串来指示哪个属性已经更改。使用nameof,我们可以直接使用属性的名称。这可能看起来没什么大不了的。但是想象一下如果有人改变了属性Foo的名字会发生什么。当使用字符串时,绑定将停止工作,但编译器不会警告你。当使用nameof时,你会得到一个编译器错误,没有名称Foo的属性/参数。
请注意,有些框架使用一些反射魔法来获取属性的名称,但现在我们不再需要nameof this了。
它对ArgumentException及其衍生物非常有用:
public string DoSomething(string input)
{
if(input == null)
{
throw new ArgumentNullException(nameof(input));
}
...
现在,如果有人重构输入参数的名称,异常也将保持最新。
在以前必须使用反射来获取属性或参数名称的某些地方,它也很有用。
在你的例子中,nameof(T)获取类型参数的名称-这也很有用:
throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method.");
nameof的另一种用法是用于枚举——通常如果你想要枚举的字符串名称,你可以使用.ToString():
enum MyEnum { ... FooBar = 7 ... }
Console.WriteLine(MyEnum.FooBar.ToString());
> "FooBar"
这实际上相对较慢,因为. net保存枚举值(即7)并在运行时查找名称。
用nameof代替:
Console.WriteLine(nameof(MyEnum.FooBar))
> "FooBar"
现在。net在编译时将枚举名称替换为字符串。
还有一种用法是INotifyPropertyChanged和日志记录——在这两种情况下,你都想把你调用的成员的名字传递给另一个方法:
// Property with notify of change
public int Foo
{
get { return this.foo; }
set
{
this.foo = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.Foo));
}
}
还是……
// Write a log, audit or trace for the method called
void DoSomething(... params ...)
{
Log(nameof(DoSomething), "Message....");
}
它在使用ASP时具有一定的优势。净MVC。当你使用HTML helper在视图中构建一些控件时,它使用HTML输入的name属性中的属性名:
@Html.TextBoxFor(m => m.CanBeRenamed)
它是这样的:
<input type="text" name="CanBeRenamed" />
所以现在,如果你需要在validate方法中验证你的属性,你可以这样做:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
if (IsNotValid(CanBeRenamed)) {
yield return new ValidationResult(
$"Property {nameof(CanBeRenamed)} is not valid",
new [] { $"{nameof(CanBeRenamed)}" })
}
}
如果你使用重构工具重命名你的属性,你的验证不会被破坏。