Подтвердить что ты не робот

Почему nameof возвращает только фамилию?

nameof (order.User.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))
4b9b3361

Ответ 1

Обратите внимание, что если вам нужно/нужно "полное" имя, вы можете сделать это:

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

, пока все эти имена находятся в текущей области.

Очевидно, что в этом случае это не все то, что полезно (имена не будут в области в вызове Razor), но это может быть, если вам нужно, например, полное имя пространства имен для типа для вызова на Type.GetType() или что-то в этом роде.

Если имена не указаны в области видимости, вы все равно можете сделать несколько более неуклюжие:

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

- хотя шансы, по крайней мере, одного из них должны быть в области видимости (если User.Age не является статическим свойством).

Ответ 2

Потому что это именно то, что было изобретено. Поскольку вы можете читать уже связанные обсуждения, здесь вы используете оператор nameof как nameof(member-access), формы E.I<A1…AK>, который будет вернуться:

Все эти случаи разрешаются с использованием правил простого поиска имен $7.6.2 или доступа к члену $7.6.4. Если они преуспевают в привязке, они должны привязываться к одному из:

     
  •   
  • Группа методов. Это приводит к ошибке "Чтобы указать имя метода, вы должны указать его аргументы".  
  • Переменная, значение, параметр, константа, член перечисления, свойство-доступ, поле, событие, параметр типа, пространство имен или тип. В этом случае результатом имени оператора является просто "I" , который обычно является именем символа, к которому привязан аргумент. Есть некоторые оговорки...  

Таким образом, в этом случае по определению он должен оценивать все выражения перед всеми точками, шаг за шагом, а затем оценивать последний, чтобы получить его Name:

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

Ответ 3

Одной из важных целей использования nameof является получение последнего "имени" в выражении.

Например, параметр nameof при броске 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

Ответ 4

Взгляните на этот метод, взятый из:

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

Ответ 5

Если вы хотите получить полное имя, вы всегда можете перейти в "старую школу".

var fullyQualifiedName = typeof(A).FullName'

Ответ 6

У меня была та же проблема, и я реализовал класс, который заменяет ключевое слово 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);