为什么nameof只返回姓氏?

时间:2015-01-12 08:50:15

标签: .net c#-6.0 nameof

nameof(order.User.Age)仅返回“Age”而不是“order.User.Age”

以更有限的方式做到这一点的原因是什么? 如果我们只想要姓氏,我们可以做类似

的事情
public static GetLastName(this string x) { 
    return string.Split(x, '.').Last();
}
nameof(order.User.Age).GetLastName()

有了一个操作员,我们可以同时获得“Age”和“order.User.Age”。 但是根据目前的实施情况,我们只能获得“年龄”。

这个决定背后有什么逻辑吗?

编辑:例如,MVC绑定需要此类行为

Html.TextBox(nameof(order.User.Age))

5 个答案:

答案 0 :(得分:15)

请注意,如果您需要/需要"完整"名字,你可以这样做:

$"{nameof(order)}.{nameof(User)}.{nameof(Age)}".GetLastName();

只要所有这些名称都在当前范围内

显然在这种情况下它并没有真正有用(名字不会在Razor调用中占据范围),但可能是你需要,例如,完整的命名空间限定名称调用Type.GetType()或类似内容的类型。

如果名称不在范围内,你仍然可以做得更笨重:

$"{nameof(order)}.{nameof(order.User)}.{nameof(order.User.Age)}".GetLastName();

- 虽然机会中至少有一个应该在范围内(除非User.Age是静态属性)。

答案 1 :(得分:8)

因为它正是为它所发明的。正如您在already linked discussions中所读到的那样,您可以使用nameof作为nameof(member-access)的{​​{1}}运算符,其中E.I<A1…AK>将返回:

  
    

使用简单名称查找规则$ 7.6.2或成员访问$ 7.6.4解决了这些情况。如果他们成功绑定,他们必须绑定到以下之一:

         
        
  • 方法组。这会产生错误&#34;要指定方法的名称,您必须提供其参数&#34;。
  •     
  • 变量,值,参数,常量,枚举成员,属性访问,字段,事件,类型参数,命名空间或类型。 在这种情况下,nameof运算符的结果只是&#34; I&#34; ,它通常是参数绑定到的符号的名称。有一些警告......
  •     
  

因此,在这种情况下,根据其定义,它必须在所有点之前逐步评估所有表达式,然后评估最后一个表达式以获得其Name

order.User.Age --> User.Age --> Age

答案 2 :(得分:3)

使用nameof的一些重要目的是获取最后一个&#34;名称&#34;在表达中。

例如,在抛出ArgumentNullException时参数名称:

void Method(string parameter)
{
     if (parameter == null) throw new ArgumentNullException(nameof(parameter));
}

MVC行动链接

<%= Html.ActionLink("Sign up",
    @typeof(UserController),
    @nameof(UserController.SignUp))
%>

INotifyPropertyChanged的

int p {
    get { return this._p; }
    set { this._p = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.p)); }
}

更多信息:https://roslyn.codeplex.com/discussions/570551

答案 3 :(得分:3)

看看这个方法取自:

https://github.com/okhosting/OKHOSTING.Data/blob/master/src/PCL/OKHOSTING.Data/Validation/MemberExpression.cs

public static string GetMemberString(System.Linq.Expressions.Expression<Func<T, object>> member)
    {
        if (member == null)
        {
            throw new ArgumentNullException("member");
        }

        var propertyRefExpr = member.Body;
        var memberExpr = propertyRefExpr as System.Linq.Expressions.MemberExpression;

        if (memberExpr == null)
        {
            var unaryExpr = propertyRefExpr as System.Linq.Expressions.UnaryExpression;

            if (unaryExpr != null && unaryExpr.NodeType == System.Linq.Expressions.ExpressionType.Convert)
            {
                memberExpr = unaryExpr.Operand as System.Linq.Expressions.MemberExpression;

                if(memberExpr != null)
                {
                    return memberExpr.Member.Name;
                }
            }
        }
        else
        {
            //gets something line "m.Field1.Field2.Field3", from here we just remove the prefix "m."
            string body = member.Body.ToString();
            return body.Substring(body.IndexOf('.') + 1);
        }

        throw new ArgumentException("No property reference expression was found.", "member");
    }

答案 4 :(得分:1)

我遇到了同样的问题,并实现了一个类来替换nameof()关键字,以获取所提供表达式的全名。 OK HOSTING答案极大地启发了它。一切都准备好了,随时可以使用:

public static class NameOf<TSource>
{
    #region Public Methods

    public static string Full(Expression<Func<TSource, object>> expression)
    {
        var memberExpression = expression.Body as MemberExpression;
        if (memberExpression == null)
        {
            var unaryExpression = expression.Body as UnaryExpression;
            if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert)
                memberExpression = unaryExpression.Operand as MemberExpression;
        }

        var result = memberExpression.ToString();
        result = result.Substring(result.IndexOf('.') + 1);

        return result;
    }

    public static string Full(string sourceFieldName, Expression<Func<TSource, object>> expression)
    {
        var result = Full(expression);
        result = string.IsNullOrEmpty(sourceFieldName) ? result : sourceFieldName + "." + result;
        return result;
    }

    #endregion
}

在您的代码中使用它看起来像:

class SpeciesFamily
{
    public string Name { get; set; }
}

class Species
{
    public SpeciesFamily Family { get; set; }
    public string Name { get; set; }
}

class Cat
{
    public Species Species { get; set; }
}

// Will return a string containing "Species.Family.Name".
var fullName = NameOf<Cat>.Full(c => c.Species.Family.Name);

// Will return a string containing "cat.Species.Name".
var fullNameWithPrefix = NameOf<Cat>.Full("cat", c => c.Species.Name);