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

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

知道目的吗?


当前回答

我发现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 },
    }
}

其他回答

正如其他人已经指出的那样,操作符的名称确实插入了源代码中给出的元素名称。

我想补充一点,这在重构方面是一个非常好的想法,因为它使得字符串重构是安全的。以前,我使用了一个静态方法,它利用反射来达到同样的目的,但这对运行时性能有影响。操作符的名称对运行时性能没有影响;它在编译时完成它的工作。如果查看MSIL代码,就会发现嵌入了字符串。请参阅下面的方法及其反汇编代码。

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

然而,如果您打算让软件变得模糊,这可能是一个缺点。经过混淆处理后,嵌入的字符串可能不再匹配元素的名称。依赖于此文本的机制将会崩溃。例如,包括但不限于:Reflection, NotifyPropertyChanged…

在运行时确定名称会损失一些性能,但对于混淆是安全的。如果混淆既不需要也不计划,我建议使用操作符的名称。

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

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

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))]

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

nameof关键字的用法之一是在wpf中以编程方式设置Binding。

要设置绑定,你必须设置路径字符串和nameof关键字,可以使用重构选项。

例如,如果你在你的UserControl中有IsEnable依赖属性,你想把它绑定到你的UserControl中某些复选框的IsEnable上,你可以使用这两个代码:

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

很明显,第一个代码不能重构,但第二个代码……

nameof的目的是重构。例如,当你在代码中其他地方通过nameof引用一个类的名字时,你会得到一个编译错误,这是你想要的。如果你没有使用nameof,只有一个普通的字符串作为引用,你必须全文搜索类的名称才能更改它。那是一种痛苦。有了nameof,您就可以轻松地在IDE中自动构建和获取所有需要更改的用例。

之前我们使用的是这样的东西:

// 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)
{
    ...
}

原因-编译时安全。没有人可以默默地重命名属性并破坏代码逻辑。现在我们可以使用nameof()。