6.0版获得了nameof的新功能,但我不能理解它的目的,因为它只是接受变量名并在编译时将其更改为字符串。

我认为它在使用<T>时可能有一些目的,但当我尝试命名(T)时,它只是打印我一个T而不是使用的类型。

知道目的吗?


当前回答

如果您想重用属性名,例如根据属性名抛出异常,或者处理PropertyChanged事件,该怎么办呢?在许多情况下,您都希望拥有属性的名称。

举个例子:

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

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

在第一种情况下,如果不同时更改属性定义和nameof(SomeProperty)表达式,则重命名SomeProperty将导致编译错误。在第二种情况下,重命名SomeOtherProperty或更改“SomeOtherProperty”字符串将导致无声地破坏运行时行为,在构建时没有错误或警告。

这是一种非常有用的方法,可以保持代码的编译和(在某种程度上)没有错误。

(Eric Lippert写了一篇很好的文章,为什么infoof没有入选,而nameof却入选了)

其他回答

假设您需要在代码中打印一个变量的名称。如果你这样写:

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

然后如果有人重构代码并使用另一个名称myVar,他/她将不得不在你的代码中寻找字符串值并相应地更改它。

相反,如果你这样写:

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

这将有助于自动重构!

操作符名称的目的是提供工件的源名称。

通常源名称与元数据名称相同:

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));
    }
}

但情况并非总是如此:

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

Or:

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

我给它的一个用途是命名资源:

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

事实上,在这种情况下,我甚至不需要生成的属性来访问资源,但是现在我有一个编译时检查资源是否存在。

最常见的用法是在输入验证中,例如

//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参考)

MSDN文章列出了MVC路由(这个例子让我真正理解了这个概念)。(格式化的)描述段落如下:

当报告代码中的错误时, 连接模型-视图-控制器(MVC)链接, 触发属性改变事件,等等, 你经常想要 捕获方法的字符串名称。使用nameof有助于保存代码 在重命名定义时有效。 在你必须使用字符串字面量之前 来引用定义,这在重命名代码元素时是很脆弱的 因为工具不知道检查这些字符串字面量。

公认的/评分最高的答案已经给出了几个很好的具体例子。

它在使用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)}" })
  }
}

如果你使用重构工具重命名你的属性,你的验证不会被破坏。