Xavier Peña
Xavier Peña

Reputation: 7919

Dealing with "convert to object" in a MemberExpression

I have a class that looks like this:

public class MyClass
{
  public int Id { get; set; }
  public string Name { get; set; }
}

I need to do this:

var memberExpressions = ConvertToMemberExpressions<MyClass>(o => o.Id, o => o.Name);

...

public static List<MemberExpression> ConvertToMemberExpressions<T>(params Expression<Func<T, object>>[] methodExpressions)
{
    var results = new List<MemberExpression>();
    foreach(var methodExpression in methodExpressions)
    {
        var memberExpression = methodExpression.Body as MemberExpression;
        results.Add(memberExpression);
    }
    return results;
}

The problem is that because of Func<T, object> (to be able to include both int and string as parameters) my methodExpression looks like this: {o => Convert(o.Id, Object)}, which is not what I need. I need to reach o.Id.

This does not happen with strings: {o => o.Name}, no conversion here.

I use Func<T,object> to be able to take advantage of Intellisense and reach the props of MyClass. I have tried using Func<T, dynamic> instead, but the result is the same.

It could be solved using multiple overloads:

public static ConvertToMemberExpressions<TClass, T1>(Expression<Func<TClass,T1>>[] methodExpression1)
public static ConvertToMemberExpressions<TClass, T1, T2>(Expression<Func<TClass,T1>>[] methodExpression1, Expression<Func<TClass,T2>>[] methodExpression2)
...

...but it is a sacrifice I would like to avoid if possible.


The question:

Is it possible to build o => o.Id from o => Convert(o.Id, Object) ?

Upvotes: 1

Views: 552

Answers (1)

canton7
canton7

Reputation: 42235

Just check whether your methodExpression.Body is a UnaryExpression with a NodeType of Convert:

public static List<MemberExpression> ConvertToMemberExpressions<T>(params Expression<Func<T, object>>[] methodExpressions)
{
    var results = new List<MemberExpression>();
    foreach (var methodExpression in methodExpressions)
    {
        var expr = methodExpression.Body;
        if (expr is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert)
        {
            expr = unaryExpression.Operand;
        }

        if (expr is MemberExpression memberExpression)
        {
            results.Add(memberExpression);
        }
        else
        {
            throw new ArgumentException($"Unexpected expression type {expr.NodeType}");
        }
    }
    return results;
}

When working with expressions, the debugger is your friend:

Image of the Watch window on expr, showing the type and the values for NodeType and Operand

Upvotes: 3

Related Questions