Sorry for the VB, but the following extract is the bit of code I meant in my comment. I don't think it covers all the bases (i.e. it may not be drilling down far enough so make sure you test it) but for simple most examples it works:
The code is based on this MSDN Expression Visitor example:
class CustomExpressionWalker<TSource> : ExpressionVisitor
{
protected override Expression VisitMemberAccess(MemberExpression m)
{
if (m.Member.DeclaringType != typeof(TSource))
{
// We are accessing a member/variable on a class
// We need to descend the tree through the navigation properties and eventually derive a constant expression
return this.VisitMemberAccess(m, m.Type);
}
throw new NotImplementedException();
}
protected Expression VisitMemberAccess(MemberExpression m, Type expectedType)
{
if (m.Expression.NodeType == ExpressionType.Constant)
{
// We are at the end of the member expression
// i.e. MyClass.Something.Something.Value <-- we're at the Value part now
ConstantExpression constant = (ConstantExpression)m.Expression;
return Expression.Constant(m.Expression.Type.GetFields().Single(n => n.FieldType == expectedType && m.Member.Name.Contains(n.Name)).GetValue(constant.Value));
}
else if (m.Member.DeclaringType == typeof(TSource))
{
// I'm unsure of your current implementation but the original Member access
// regarding serializing the expression, but if the code reaches here a nested
// MemberAccess has landed on a Property/variable of type TSource, so you'll need
// to decide whether to serialize here or not. For example, if TSource was of
// type "myClass", it could be
// (myOtherClass x) => x.myClass
throw new NotImplementedException();
}
else if (m.Member.DeclaringType == typeof(Nullable))
{
// never got round to implementing this as we don't need it yet
// if you want to deal with Nullable<T> you're going to have to
// examine the logic here
throw new NotImplementedException();
}
else
{
// continue walking the member access until we derive the constant
return this.VisitMemberAccess((MemberExpression)m.Expression, expectedType);
}
}
}
Hope this helps!
EDIT: The original issue I had was that I didn't continue walking the tree when the MemberAccess was a non TSource
class, the above logic should actually recursively root those cases out so ignore my original comment. I've left in the Nullable<T>
clause (on the else if
) statement as I don't think the existing logic will cover those cases, it may also struggle with Generic classes.
That said, this should put you in good stead. If you're not using the Expression Visitor, can you provide some more details/code?
Good luck!