Есть ли лучший способ получить имя свойства при передаче через лямбда-выражение? Вот что у меня сейчас есть.
например.
GetSortingInfo<User>(u => u.UserId);
Он работал, выражая его как выражение, только когда свойство было строкой. потому что не все свойства являются строками, я должен был использовать объект, но тогда он вернул бы унарное выражение для них.
public static RouteValueDictionary GetInfo<T>(this HtmlHelper html,
Expression<Func<T, object>> action) where T : class
{
var expression = GetMemberInfo(action);
string name = expression.Member.Name;
return GetInfo(html, name);
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");
MemberExpression memberExpr = null;
if (lambda.Body.NodeType == ExpressionType.Convert)
{
memberExpr =
((UnaryExpression)lambda.Body).Operand as MemberExpression;
}
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpr = lambda.Body as MemberExpression;
}
if (memberExpr == null)
throw new ArgumentException("method");
return memberExpr;
}
c#
linq
lambda
expression-trees
Schotime
источник
источник
MemberExpression
подход, перечисленный здесь, только для получения имени члена, а не для полученияMemberInfo
самогоMemberInfo
факта , поскольку в определенных сценариях «dervied: base» гарантированный тип не гарантированно будет отраженного типа. См. Lambda-expression-not-returning-Ожидаемый-memberinfo . Споткнул меня однажды. Принятый ответ тоже страдает от этого.Ответы:
Недавно я сделал очень похожую вещь, чтобы сделать безопасный метод типа OnPropertyChanged.
Вот метод, который возвращает объект PropertyInfo для выражения. Выдает исключение, если выражение не является свойством.
source
Параметр используется для того , компилятор может сделать вывод типа вызова метода. Вы можете сделать следующееисточник
u => u.OtherType.OtherTypesProperty
создаст такой случай, что последний оператор проверяет.if (type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType) && !propInfo.ReflectedType.IsAssignableFrom(type))
разрешить интерфейсы тоже.if(!propInfo.ReflectedType.IsAssignableFrom(type))
?Я нашел другой способ, которым вы могли бы сделать, это строго определить тип источника и свойства и явно сделать вывод для лямбда-выражения. Не уверен, что это правильная терминология, но вот результат.
А потом назови это так.
и вуаля это работает.
Спасибо всем.
источник
GetInfo(nameof(u.UserId))
var name = ((MemberExpression) ((UnaryExpression) accessor.Body).Operand).Member.Name
Я играл с тем же самым и работал над этим. Он не полностью протестирован, но, похоже, решает проблему с типами значений (проблема с одним выражением, с которой вы столкнулись)
источник
o => o.Thing1.Thing2
вернетсяThing2
, нетThing1.Thing2
, что неправильно, если вы пытаетесь использовать его в EntityFramework включает в себяЭто обрабатывает член и унарные выражения. Разница в том, что вы получите,
UnaryExpression
если ваше выражение представляет тип значения, тогда как вы получите,MemberExpression
если ваше выражение представляет ссылочный тип. Все может быть приведено к объекту, но типы значений должны быть упакованы. Вот почему существует UnaryExpression. Ссылка.Ради читабельности (@Jowen), вот расширенный эквивалент:
источник
С C # 7 сопоставления с образцом:
Пример:
[Обновление] C # 8 соответствия шаблону:
источник
теперь в C # 6 вы можете просто использовать nameof, как это
nameof(User.UserId)
что имеет много преимуществ, среди которых то, что это делается во время компиляции , а не во время выполнения.
https://msdn.microsoft.com/en-us/magazine/dn802602.aspx
источник
Это общая реализация для получения строкового имени полей / свойств / индексаторов / методов / методов расширения / делегатов структуры / класса / интерфейса / делегата / массива. Я проверил с комбинациями статических / экземпляра и неуниверсальных / универсальных вариантов.
Это тоже можно записать в простой
while
цикл:Мне нравится рекурсивный подход, хотя второй может быть легче читать. Это можно назвать так:
распечатать последний член.
Замечания:
В случае цепных выражений типа
A.B.C
«C» возвращается.Это не работает с
const
s, индексаторами массива илиenum
s (невозможно охватить все случаи).источник
Есть крайний случай, когда дело доходит до.
Array
Длина. Хотя «Длина» выставляется как свойство, его нельзя использовать ни в одном из ранее предложенных решений.Теперь пример использования:
Если
PropertyNameFromUnaryExpr
не проверятьArrayLength
, «someArray» будет выводиться на консоль (кажется, что компилятор генерирует прямой доступ к полю Backing Length , как оптимизация, даже в Debug, таким образом, в особом случае).источник
Вот обновление метода, предложенного Кэмероном . Первый параметр не обязателен.
Вы можете сделать следующее:
Методы расширения:
Вы можете:
источник
u
как некоторый тип, он не может сделать это, потому что нет типа, чтобы выводить. Что вы можете сделать, этоGetPropertyInfo<SomeType>(u => u.UserID)
Я обнаружил, что некоторые из предложенных ответов, которые углубляются в
MemberExpression
/UnaryExpression
не охватывают вложенные / подвойства.пр)
o => o.Thing1.Thing2
возвращается,Thing1
а неThing1.Thing2
.Это различие важно, если вы пытаетесь работать с EntityFramework
DbSet.Include(...)
.Я обнаружил, что просто анализ,
Expression.ToString()
кажется, работает нормально и сравнительно быстро. Я сравнил это сUnaryExpression
версией, и даже вылезToString
из нее,Member/UnaryExpression
чтобы увидеть, было ли это быстрее, но разница была незначительной. Пожалуйста, поправьте меня, если это ужасная идея.Метод продления
(Проверка на разделитель может быть даже излишней)
Демо (LinqPad)
Демонстрация + код сравнения - https://gist.github.com/zaus/6992590
источник
o => o.Thing1.Thing2
не возвращается ,Thing1
как вы говорите , ноThing2
. На самом деле ваш ответ возвращает что-то вроде того,Thing1.Thing2
что может или не может быть желательным.Thing1.Thing2
, никогдаThing1
. Я сказал ,Thing2
имея в виду значение изo.Thing1.Thing2
, которая является точкой предиката. Я обновлю ответ, чтобы отразить это намерение.Thing1
? Я не думаю, что это перенастраивает это вообще.Я использую метод расширения для проектов до C # 6 и nameof () для тех, кто ориентирован на C # 6.
И я называю это так:
Он отлично работает как с полями, так и со свойствами.
источник
Ну, не нужно звонить
.Name.ToString()
, но в целом это все, да. Единственное, что вам может понадобиться, - этоx.Foo.Bar
возвращать ли "Foo", "Bar" или исключение - т.е. нужно ли вам вообще выполнять итерации.(re comment) Подробнее о гибкой сортировке см. здесь .
источник
ToString
должен давать некрасивые результаты для унарных выражений.Я создал метод расширения для ObjectStateEntry, чтобы иметь возможность помечать свойства (классов POCO Entity Framework) как измененные безопасным способом, поскольку метод по умолчанию принимает только строку. Вот мой способ получить имя от собственности:
источник
Я сделал
INotifyPropertyChanged
реализацию, похожую на метод ниже. Здесь свойства хранятся в словаре в базовом классе, показанном ниже. Конечно, не всегда желательно использовать наследование, но для моделей представлений я думаю, что это приемлемо и дает очень чистые ссылки на свойства в классах моделей представлений.Несколько более сложный базовый класс показан ниже. Он обрабатывает перевод из лямбда-выражения в имя свойства. Обратите внимание, что свойства действительно являются псевдо-свойствами, так как используются только имена. Но он будет прозрачным для модели представления и ссылок на свойства модели представления.
источник
public bool IsLoading { get { return GetValue(MethodBase.GetCurrentMethod().Name); } set { SetPropertyValue(MethodBase.GetCurrentMethod().Name, value); } }
. Может быть медленнее, но более общим и простым.Это еще один ответ:
источник
ModelMetadata
существует вSystem.Web.Mvc
пространстве имен. Может быть, это не подходит для общего случаяЯ оставляю эту функцию, если вы хотите получить несколько полей:
источник
Вот еще один способ получить PropertyInfo на основе этого ответа. Это устраняет необходимость в экземпляре объекта.
Это можно назвать так:
источник
Я обновил ответ @ Cameron, включив в него некоторые проверки безопасности для
Convert
напечатанных лямбда-выражений:источник
Начиная с .NET 4.0 вы можете использовать
ExpressionVisitor
для поиска свойств:Вот как вы используете этого посетителя:
источник
Это может быть оптимальным
источник
источник