Why does nameof return only last name?

前端 未结 5 811
南笙
南笙 2020-12-16 09:45

nameof(order.User.Age) return only Age instead of order.User.Age

What is the reason to do it in more restricted way? If we wan

相关标签:
5条回答
  • 2020-12-16 10:01

    Because it is exactly what for it've been invented. As you can read in already linked discussions, here you using the nameof operator as nameof(member-access), of the form E.I<A1…AK>, which will return:

    These cases are all resolved using the rules for simple name lookup $7.6.2 or member access $7.6.4. If they succeed in binding, they must bind to one of:

    • A method-group. This produces an error "To specify the name of a method, you must provide its arguments".
    • A variable, value, parameter, constant, enumeration-member, property-access, field, event, type-parameter, namespace or type. In this case the result of the nameof operator is simply "I", which is generally the name of the symbol that the argument bound to. There are some caveats…

    So in this case it, by its definition, have to evaluate all expressions before all the dots, step by step, and after that evaluate the last one to get its Name:

    order.User.Age --> User.Age --> Age
    
    0 讨论(0)
  • 2020-12-16 10:01

    Some of the important purposes of using nameof is to get the last "name" in the expression.

    For example nameof parameter when throwing ArgumentNullException:

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

    MVC Action links

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

    More information: https://roslyn.codeplex.com/discussions/570551

    0 讨论(0)
  • 2020-12-16 10:06

    Take a look at this method taken from:

    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");
        }
    
    0 讨论(0)
  • 2020-12-16 10:15

    Note that if you need/want the "full" name, you could do this:

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

    as long as all of these names are in the current scope.

    Obviously in this case it's not really all that helpful (the names won't be in scope in the Razor call), but it might be if you needed, for example, the full namespace qualified name of a type for a call to Type.GetType() or something.

    If the names are not in scope, you could still do the somewhat more clunky:

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

    -- although chances are at least one of those should be in scope (unless User.Age is a static property).

    0 讨论(0)
  • 2020-12-16 10:16

    I had the same problem and implemented a class that acts as a replacement of the nameof() keyword in order to get the full name of the expression being supplied. It's greatly inspired from OK HOSTING answer. It's just all baked and ready to use:

    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
    }
    

    Using it in your code would look like:

    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);
    
    0 讨论(0)
提交回复
热议问题