I'm trying to use the ExpressionVisitor
to get an overridden member of an expression but it's giving me the base one. What am I missing here?
The following example reproduces this behaviour:
Simple base and derived types:
class Base
{
public virtual string Property { get; set; }
}
class Derived : Base
{
public override string Property { get; set; }
}
I use this expression visitor:
internal class DemoVisitor : ExpressionVisitor
{
private MemberInfo _member;
public static MemberInfo GetMemberInfo(LambdaExpression expression)
{
var visitor = new DemoVisitor();
visitor.Visit(expression);
return visitor._member;
}
protected override Expression VisitMember(MemberExpression node)
{
// invalid member here
//node.Member.DeclaringType.Name.Dump();
_member = _member ?? node.Member;
return base.VisitMember(node);
}
}
Calling it like that
void Main()
{
var derived = new Derived();
var expression = (Expression<Func<string>>)(() => derived.Property);
DemoVisitor.GetMemberInfo(expression).DeclaringType.Name.Dump();
}
This returns Base
instead of Derived
. What do I have to do to get to the overridden member?
I need it because I'm reading its attributes later and it's currently giving me the attributes of the property on the base class instead of the derived one.
If you want to know the type of the class/struct of your member you need to look at the MemberExpression
's Expression property which is the expression for the object containing the member - in your case the derived
variable - and get its type.
Therefore your visitor needs to return both (here I used a ValueTuple):
internal class DemoVisitor : ExpressionVisitor
{
private Type type;
private MemberInfo _member;
public static (Type, MemberInfo) GetMemberInfo(LambdaExpression expression)
{
var visitor = new DemoVisitor();
visitor.Visit(expression);
return (visitor.type, visitor._member);
}
protected override Expression VisitMember(MemberExpression node)
{
if (_member == null)
{
_member = node.Member;
type = node.Expression.Type;
}
return base.VisitMember(node);
}
}
Regarding your other question about which member gets visited: all used members in your expression get visited, i.e. all methods, properties and fields, whereas node.Member returns either a MethodInfo
, PropertyInfo
or FieldInfo
object, which all derive from MemberInfo
.