从Lambda表达式中提取属性链

时间:2018-11-09 12:14:17

标签: c# .net lambda

假设我有以下代码:

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 :(得分:1)

非常便宜的方式是这样的:

  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”,然后执行{{ 1}}在循环后的堆栈上。

无论哪种情况,都可以通过调用我的方法.ToArray()

更长的示例调用:DoSomething((DateTime x) => x.TimeOfDay.TotalHours);

如果您想找回普通的DoSomething((System.Threading.Thread x) => x.CurrentCulture.NumberFormat.NumberDecimalSeparator.Length);,请使用:

Func<,>

我确信可以通过多种方式对此进行改进。

答案 1 :(得分:0)

有可能,但是您需要继续使用ExpressionTree,而不仅仅是一个func。请从我们心爱的Microsoft网站上查看官方documentation。实际上,这需要大量的反思,所以如果必须要有性能,那就不要这样做。在这种情况下,您必须将更多信息发送到您的方法中,例如元组(function, metadata)