#c#
#.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
. Но с текущей реализацией мы можем получить только Age
. Есть ли какая-то логика в этом решении? Например, такое поведение необходимо для привязки MVC
Html.TextBox(nameof(order.User.Age))
Комментарии:
1. Обратите
order.User
внимание, что также может быть некоторой функцией, возвращающей объект со свойствомName
. На что должен ссылаться nameof в таких случаях?2.
nameof
это постоянная времени компиляции, так как же она будет работать на экземпляре?3. Чтобы узнать почему, вам придется пройти через долгие обсуждения на roslyn.codeplex.com
4. @leppie для этого есть три варианта использования, как видно из обсуждений Roslyn.
5. Почему это помечено как версия c #-6.0, .net-5.0. 5 или 6, о которой мы говорим?
Ответ №1:
Обратите внимание, что если вам нужно / нужно «полное» имя, вы могли бы сделать это:
$"{nameof(order)}.{nameof(User)}.{nameof(Age)}".GetLastName();
пока все эти имена находятся в текущей области.
Очевидно, что в данном случае это не совсем так полезно (имена не будут находиться в области видимости при вызове Razor), но это может быть, если вам нужно, например, полное имя пространства имен определенного типа для вызова Type.GetType()
или что-то в этом роде.
Если имена не входят в область видимости, вы все равно можете сделать несколько более неуклюжий:
$"{nameof(order)}.{nameof(order.User)}.{nameof(order.User.Age)}".GetLastName();
— хотя есть вероятность, что хотя бы один из них должен быть в области видимости (если User.Age
это не статическое свойство).
Комментарии:
1. Это не работает, так
nameof
как должно быть полностью указано. Таким образом, это выглядело бы так$"{nameof(order)}.{nameof(order.User)}.{nameof(order.User.Age)}"
, точно указывая точку операции.2. Это абсолютно работает — nameof не нужно указывать полностью, параметры для него просто должны быть в области видимости. Возможно, я предполагал, что все эти имена были в области видимости, но это не значит, что это не работает. Очевидно, что если вы пытаетесь использовать его в другой области, они должны быть квалифицированы, но я не понимаю, как это действительно влияет на ответ.
3. Возможно, я неправильно сформулировал это, указав «полностью квалифицированный». Однако это влияет на ответ, поскольку, судя по моему прочтению OP, они не все находятся в области видимости.
4. как это
$"{nameof(order)}.{nameof(User)}.{nameof(Age)}".GetLastName();
имеет смысл? Для того, чтобы эти свойства были «в области видимости»order
, должны бытьthis
иUser
иAge
должны быть свойствами, дляthis
которых они не являются:/ Это не отвечает на вопрос op. И что, черт возьми, находитсяGetLastName()
в строке?5. Очень маловероятно, что вы бы так не сказали.
Ответ №2:
Потому что это именно то, для чего это было изобретено. Как вы можете прочитать в уже связанных обсуждениях, здесь вы используете nameof
оператор as nameof(member-access)
формы E.I<A1…AK>
, который вернет:
Все эти случаи разрешаются с использованием правил простого поиска имен $ 7.6.2 или доступа к участникам $ 7.6.4. Если им удается выполнить привязку, они должны привязаться к одному из:
- Метод-группа. Это приводит к ошибке «Чтобы указать имя метода, вы должны предоставить его аргументы».
- Переменная, значение, параметр, константа, элемент перечисления, доступ к свойству, поле, событие, параметр типа, пространство имен или тип. В этом случае результатом оператора nameof является просто «I», который обычно является именем символа, с которым связан аргумент. Есть несколько предостережений…
Итак, в этом случае он, по его определению, должен вычислять все выражения перед всеми точками, шаг за шагом, и после этого вычислять последнее, чтобы получить его Name
:
order.User.Age --> User.Age --> Age
Ответ №3:
У меня была та же проблема, и я реализовал класс, который действует как замена 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 amp;amp; unaryExpression.NodeType == ExpressionType.Convert)
memberExpression = unaryExpression.Operand as MemberExpression;
}
var result = memberExpression.ToString();
result = result.Substring(result.IndexOf('.') 1);
return resu<
}
public static string Full(string sourceFieldName, Expression<Func<TSource, object>> expression)
{
var result = Full(expression);
result = string.IsNullOrEmpty(sourceFieldName) ? result : sourceFieldName "." resu<
return resu<
}
#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);
Комментарии:
1. Если вы передаете массив в выражение. Например, возьмите это выражение
phone => phone.Lines[1].AsteriskSipPeer
, которое оно вернетLines.get_Item(1).AsteriskSipPeer
. Я просто добавил это регулярное выражение, чтобы позаботиться об этомresult = Regex.Replace(result, @"(?x) get_Item ( (d ) )", m=> $"[{m.Groups[1].Value}]")
Ответ №4:
Взгляните на этот метод, взятый из:
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 amp;amp; 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:
Некоторые из важных целей использования 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
Комментарии:
1. Как насчет привязки MVC к Html.TextBox(nameof(User.Name ))?
2. Ммм, «все цели»? Нет, я бы сказал обратное. Например, когда вы сталкиваетесь с неожиданной нулевой ссылкой и хотите зарегистрировать ошибку, но не хотите создавать исключение, вы хотели бы предоставить как можно больше контекста относительно того, что именно было null . Возьмем этот пример: Экземпляр. Окно. textLabel . Текстовое поле. StringLabel . Значение. Ссылка. Объект. Предположим, что «Объект» равен нулю. Что было бы более полезно для диагностики?: просто «Объект» или «Экземпляр. Окно. textLabel . Текстовое поле. StringLabel . Значение. Ссылка. Объект»?
3. Я бы сказал, что null — это что-то совсем другое, но если вы посмотрите на случаи с хлебом и маслом, перечисленные в ссылке, ведение журнала также присутствует, исходя из этого, ваш случай, вероятно, будет зарегистрирован следующим образом:
MyMethod(InsaneTypeThatIsNull myVar) { Log(nameof(MyMethod), $"{nameof(myVar)} was null"); }
легко отследить это и найти тип4. @ais для привязки к MVC вы должны написать шаблон редактирования для своей пользовательской модели, а затем использовать @Html.EditorFor(x => x.User)