2

I'm attempting to retrieve the value of a property from an instance of MemberExpression.

Here is what I have so far:

protected override void VisitMember(Context context, MemberExpression node)
{              
    var propertyInfo = node.Member as PropertyInfo;
    if(propertyInfo != null)
    {
       var v = propertyInfo.GetValue(node.Member , null);
       val = Convert.ToString(v);
    }
    context.State.Append(val);
}

Depending on the approach I take there are two problems: I don't know the expected type (string, int, etc...), and/or I have not been able access the instance from the MemberExpression.

I am writing a small lambda expressions to T-SQL converter. For example (u)=> u.FirstName == u.LastName; would convert to FirstName = 'chuck'. I've almost got it working!

update

I tried the following code:

...  

var propertyInfo = node.Member as PropertyInfo;

if(propertyInfo != null)
{
   var o = propertyInfo.GetValue(node.Expression, null);
}

...

It did not work. I get the following error:

System.Reflection.TargetException : Object does not match target type.

update 2

This is what I am trying to accomplish:

    public static Func<T, object> GetValueGetter<T>(this PropertyInfo propertyInfo)
    {
        if (typeof(T) != propertyInfo.DeclaringType)
        {
            throw new ArgumentException();
        }

        var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
        var property = Expression.Property(instance, propertyInfo);
        var convert = Expression.TypeAs(property, typeof(object));
        return (Func<T, object>)Expression.Lambda(convert, instance).Compile();
    }

But I do not know T at compile time.

Chuck Conway
  • 16,287
  • 11
  • 58
  • 101

2 Answers2

5

I don't know the expected type (string, int, etc...),

Use Expression.Type

I have not been able access the instance from the MemberExpression

Use MemberExpression.Expression - obviously that's another expression, because you might have:

foo.GetBar(20).ToString().Length

in which case the Length property would be a MemberExpression, but the Expression property would give the MethodCallExpression for ToString.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • All the examples I have seen cast with a Func (i.e. '(Func)Expression.Lambda(convert, instance).Compile();') which is a cast with a generic. Generics are of course compile time... – Chuck Conway Mar 19 '12 at 23:21
  • ... my issue is, I don't know the type until runtime. – Chuck Conway Mar 19 '12 at 23:29
  • @ChuckConway: In that case you don't want a generic method, you just want something returning `Expression`, presumably. – Jon Skeet Mar 20 '12 at 06:44
0

I have not been able access the instance from the MemberExpression.

In your example u => u.FirstName == "chuck", there is no instance for which to fetch the FirstName property.

I think you actually want the name of the property - which is node.Member.Name (and is "FirstName" in your example). Note that this works for all MemberInfo, not just PropertyInfo, so fields will work as well. (You may want to test anyway, because Events are also member expressions, but don't make sense here.)

I don't know the expected type (string, int, etc...),

The expected type is either PropertyInfo.PropertyType or FieldInfo.FieldType.

porges
  • 30,133
  • 4
  • 83
  • 114
  • There is, it's passed in as the MemberExpression parameter. MemberExpresion is `u.FirstName`. I'm not looking for the name of the property. I'm seeking the value of the property. – Chuck Conway Mar 19 '12 at 23:05
  • But in a lambda expression there is no instance for which to pull the value of the property from, unless you provide it somewhere else. `u => u.FirstName` will only have an instance on which to get the value when you actually call it on some object. – porges Mar 19 '12 at 23:07
  • That makes sense. Most example I have seen are compiling the lambda expression before retrieving the property value. In these cases the type is known at compile time. In my case I do not know the type. – Chuck Conway Mar 19 '12 at 23:29
  • If you're converting `u => u.FirstName == "chuck"` to `FirstName = 'chuck'` you shouldn't need the value of the property anyway, only the name of the property - that's why I showed how to do that. – porges Mar 19 '12 at 23:34
  • ahh, good point. I updated the question. I'm trying to cover this scenerio: `u => u.FirstName == u.LastName` to `FirstName = 'chuck'` where the right hand evalution is converted to the value of the property. The leftside is the name of the property. – Chuck Conway Mar 19 '12 at 23:42
  • You have the same problem here... when you look at the Expression for `u.LastName` there's no instance to fetch a value from. – porges Mar 19 '12 at 23:55
  • @ChuckConway: Your update #2 changes things quite a bit :) If you don't know `T` at compile time, then you won't be able to return a typed `Func` - would it be possible to return a simple `Delegate` (returned by `.Compile()`) instead? It depends on what you're doing with the result of that function... – porges Mar 20 '12 at 04:46