C #: получение имен свойств в цепочке из лямбда-выражения

m разработка API, который использует лямбда-выражения для указания свойств. Я'Я использую этот известный кусок кода, похожий на этот (это упрощенный и неполный, просто чтобы прояснить, что яя говорю)

public void Foo(Expression action)
{
    var expression = (MemberExpression)action.Body;
    string propertyName = expression.Member.Name;
    // ...
}

Чтобы называться так:

Foo((String x) => x.Length);

Теперь я хотел бы указать путь к свойству путем объединения имен свойств, например:

Foo((MyClass x) => x.Name.Length);

Foo должен иметь возможность разбить путь на имена своих свойств ("Name" а также"Length"). Есть ли способ сделать это с разумными усилиями?

Eстькак-то похожий вопрос, но я думаю, что они пытаются объединить там лямбда-выражения.

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

Ответы на вопрос(3)

Решение Вопроса

Что-то вроде этого?

public void Foo(Expression expr)
{
    MemberExpression me;
    switch (expr.Body.NodeType)
    {
        case ExpressionType.Convert:
        case ExpressionType.ConvertChecked:
            var ue = expr.Body as UnaryExpression;
            me = ((ue != null) ? ue.Operand : null) as MemberExpression;
            break;
        default:
            me = expr.Body as MemberExpression;
            break;
    }

    while (me != null)
    {
        string propertyName = me.Member.Name;
        Type propertyType = me.Type;

        Console.WriteLine(propertyName + ": " + propertyType);

        me = me.Expression as MemberExpression;
    }
}
 asgerhallas19 дек. 2012 г., 13:47
@StefanSteinegger Старый вопрос, я знаю ... но если этотолько имена, которые вам нужны,expr.ToString().Split('.').Skip(1) было бы еще проще :)
 Stefan Steinegger08 янв. 2013 г., 10:18
@asgerhallas: вы можете добавить еще один ответ.
 Stefan Steinegger03 нояб. 2009 г., 16:29
Вау, это работает, и это довольно просто. Большое спасибо!

Старый вопрос, я знаю ... но если этоЕсли вам нужны только имена, еще более простой способ сделать это:

expr.ToString().Split('.').Skip(1) 

РЕДАКТИРОВАТЬ:

public class A
{
    public B Property { get; set; }
}

public class B
{
    public C field;
}

[Fact]
public void FactMethodName()
{
    var exp = (Expression) (x => x.Property.field);
    foreach (var part in exp.ToString().Split('.').Skip(1))
        Console.WriteLine(part);

    // Output:
    // Property
    // field
}
 asgerhallas11 дек. 2013 г., 09:51
@Pat Я редактировал в каком-то рабочем коде. Надеюсь, это поможет. Хотя немного поздно :)
 Pat31 июл. 2013 г., 22:12
Хм, это неработать на меня (.ToString дал только последнее имя свойства). У вас есть большой пример кода с использованием?
 Peter Morris24 авг. 2017 г., 12:21
Мне немного неудобно делать это таким образом. Предполагается, что ToString для преобразования в визуальное представление, это не• Контракт каким-либо образом, и поэтому (хотя и маловероятно) формат может быть изменен в будущем.
 nawfal18 дек. 2013 г., 21:49
ToString не будет работать в случае упаковывания типов значений, за исключением того, что они очень медленные. Просто будь осторожен.

Я немного поиграл сExpressionVisitor:

public static class PropertyPath
{
    public static IReadOnlyList Get(Expression expression)
    {
        var visitor = new PropertyVisitor();
        visitor.Visit(expression.Body);
        visitor.Path.Reverse();
        return visitor.Path;
    }

    private class PropertyVisitor : ExpressionVisitor
    {
        internal readonly List Path = new List();

        protected override Expression VisitMember(MemberExpression node)
        {
            if (!(node.Member is PropertyInfo))
            {
                throw new ArgumentException("The path can only contain properties", nameof(node));
            }

            this.Path.Add(node.Member);
            return base.VisitMember(node);
        }
    }
}

Использование:

var path = string.Join(".", PropertyPath.Get(x => x.Length).Select(p => p.Name));
 Johan Larsson17 дек. 2016 г., 13:44
Да, блокировка там тупая, обновление ответа.
 DGreen11 сент. 2018 г., 17:27
@JohanLarsson Можете ли вы вспомнить причину звонка.Reverse на пути?
 angularsen17 дек. 2016 г., 12:38
Я добавил исправленную версию без блокировки, переместил общие параметры в класс, поэтому вам нужно только указать TSource и вспомогательный метод, который возвращает строку с настраиваемым разделителем строк:gist.github.com/anjdreas/862c1cd9983d7525d2ddee0bb2706c3a
 Johan Larsson11 сент. 2018 г., 19:10
Я хотел, чтобы путь был в порядке, обратном тому, что создал посетитель :) Измените его в соответствии со своими потребностями, не забудьте написать пару тестов.
 angularsen17 дек. 2016 г., 11:58
Спасибо за ExpressionVisitor. Это было действительно чистое решение. Я бы лично создал экземпляр PathVisitor для каждого вызова метода вместо использования блокировки, но в документах ничего не говорится о рекомендациях, так или иначе, или если это тяжелый объект для создания. У него нет Dispose (), что указывает на то, что он не содержит много ресурсов.

Ваш ответ на вопрос