Извлечь цепочку свойств из лямбда-выражения - PullRequest
0 голосов
/ 09 ноября 2018

Представьте, что у меня есть следующий код:

public void DoSomething<TU,TV>(Func<TU,TV> valueGetter)
{
    TV extractedValue = valueGetter(_someFields);
    //Here, how to get from  valueGetter the properties used to get the value.
    PropertyInfo[] properties = ....;//["SubObject", "SubSubObject", "Property"]

}
DoSomething((x)=>x.SubObject.SubSubObject.Property)//Let admit that this path always contains only properties, never methods

Я слишком извлекаю массив PropertyInfo, содержащий каждое свойство в пути, чтобы получить объект через отражение.

Возможно ли это?

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Очень дешевый способ выглядит так:

  public void DoSomething<TU, TV>(Expression<Func<TU, TV>> valueGetterExpr)
  {
    var str = valueGetterExpr.ToString();
    // now 'str' holds string representation of the lambda expression
  }

Более структурированный подход похож на это:

  public void DoSomething<TU, TV>(Expression<Func<TU, TV>> valueGetterExpr)
  {
    var expr = valueGetterExpr.Body;
    var li = new List<PropertyInfo>();
    while (!(expr is ParameterExpression))
    {
      if (!(expr is MemberExpression me))
        throw new Exception("Unexpected kind");

      if (!(me.Member is PropertyInfo pi))
        throw new Exception("Unexpected kind");

      li.Add(pi);
      expr = me.Expression;
    }
    // now 'li' holds all the properties
  }

Порядок обратный по сравнению с тем, что вы сказали. Вы можете поменять List<> на месте с помощью li.Reverse();, или вы можете использовать new Stack<...>() вместо new List<...>(), «push» вместо «add» и делать .ToArray() в вашем стеке после цикла.

В любом случае, вызовите мой метод, например, DoSomething((DateTime x) => x.TimeOfDay.TotalHours);.

Более длинный пример вызова: DoSomething((System.Threading.Thread x) => x.CurrentCulture.NumberFormat.NumberDecimalSeparator.Length);

Если вы хотите вернуть Func<,> равнину, вы используете:

var func = valueGetterExpr.Compile();
var extractedValue = func(_someFields);

Я уверен, что это можно улучшить несколькими способами.

0 голосов
/ 09 ноября 2018

Возможно, однако вам нужно будет перейти на ExpressionTree, а не просто на функцию. Проверьте официальную документацию от нашего любимого Microsoft. На самом деле это потребовало бы много размышлений, так что не делайте этого, если производительность необходима; в таком случае вам нужно добавить больше информации в ваш метод, например, tuple (function, metadata).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...