This should get you pretty far - it's very hacky but I don't think there's a way around it:
Expression<Func<Employee, object>> _xxx = e => e.EmployeeInfo.Addresses[address];
WriteLine(ExprToString(_xxx)); //e.EmployeeInfo.Addresses[address]
_xxx = x => x.EmployeeInfo.Addresses["XYZ"];
WriteLine(ExprToString(_xxx)); //x.EmployeeInfo.Addresses["XYZ"]
_xxx = y => y.EmployeeInfo.Addresses[null];
WriteLine(ExprToString(_xxx)); //y.EmployeeInfo.Addresses[null]
_xxx = z => z.EmployeeInfo.Name;
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.Name
_xxx = z => z.EmployeeInfo.GetSalary();
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.GetSalary()
_xxx = z => z.EmployeeInfo.Addresses.Select(a => a.Street);
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.Addresses.Select(a.Street)
_xxx = z => z.EmployeeInfo.Array[3];
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.Array[3]
The implementation:
static string ExprToString(Expression expr)
{
switch (expr.NodeType)
{
case ExpressionType.Lambda:
//x => (Something), return only (Something), the Body
return ExprToString(((LambdaExpression) expr).Body);
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
//type casts are not important
return ExprToString(((UnaryExpression) expr).Operand);
case ExpressionType.Call:
//method call can be an Indexer (get_Item),
var callExpr = (MethodCallExpression) expr;
if (callExpr.Method.Name == "get_Item")
{
//indexer call
return ExprToString(callExpr.Object) + "[" + string.Join(",", callExpr.Arguments.Select(ExprToString)) + "]";
}
else
{
//method call
var arguments = callExpr.Arguments.Select(ExprToString).ToArray();
string target;
if (callExpr.Method.IsDefined(typeof (ExtensionAttribute), false))
{
//extension method
target = string.Join(".", arguments[0], callExpr.Method.Name);
arguments = arguments.Skip(1).ToArray();
}
else if (callExpr.Object == null)
{
//static method
target = callExpr.Method.Name;
}
else
{
//instance method
target = string.Join(".", ExprToString(callExpr.Object), callExpr.Method.Name);
}
return target + "(" + string.Join(",", arguments) + ")";
}
case ExpressionType.MemberAccess:
//property or field access
var memberExpr = (MemberExpression) expr;
if (memberExpr.Expression.Type.Name.Contains("<>")) //closure type, don't show it.
{
return memberExpr.Member.Name;
}
else
{
return string.Join(".", ExprToString(memberExpr.Expression), memberExpr.Member.Name);
}
}
//by default, show the standard implementation
return expr.ToString();
}