Reputation: 20707
Imagine I've the following code:
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
I'm looking too extract an array of PropertyInfo, containing each property in the path to get the object through reflection.
Is that possible?
Upvotes: 1
Views: 113
Reputation: 61942
The very cheap way is like this:
public void DoSomething<TU, TV>(Expression<Func<TU, TV>> valueGetterExpr)
{
var str = valueGetterExpr.ToString();
// now 'str' holds string representation of the lambda expression
}
A more structured approach is similar to this:
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
}
The order is reversed compared to what you said. You may reverse the List<>
in place with li.Reverse();
, or you can use a new Stack<...>()
instead of a new List<...>()
, "push" instead of "add", and do .ToArray()
on your stack after the loop.
In either case, call my method with e.g. DoSomething((DateTime x) => x.TimeOfDay.TotalHours);
.
Longer example call: DoSomething((System.Threading.Thread x) => x.CurrentCulture.NumberFormat.NumberDecimalSeparator.Length);
If you want to get the plain Func<,>
back, you use:
var func = valueGetterExpr.Compile();
var extractedValue = func(_someFields);
I am sure this can be improved in several ways.
Upvotes: 1
Reputation: 4109
It is possible, however you'd need to proceed on the ExpressionTree
rather than just a func. Check official documentation from our beloved Microsoft. That would require a lot of reflection, actually, so don't do if performance is a must; in such a case you have to ship more info into your method, like tuple (function, metadata)
.
Upvotes: 0