views:

253

answers:

3

I have a function:

private string GetPropertyName(Expression<Func<object, object>> f) {
    if ((f.Body as MemberExpression) != null) {
        return (f.Body as MemberExpression).Member.Name;
    }
    return "";
}

And it is used this way:

string x1 = GetPropertyName(x => Property1);
string x2 = GetPropertyName(x => Property2);
string x3 = GetPropertyName(x => Property3);

where Property1 is an int, Property2 is a string, and Property3 is an object...

Only the names of Property2 and Property3 of types string and object respectfully are correctly returned, but Property1's f.Body as MemberExpression is null...

Why is this so, and how can we change the code so the function returns the Properties' names correctly?

A: 

int, double, and bool are native types in C# - that is, they are not objects at all. In other words, there is no class definition for int - it's an interpretation of a value in raw memory. Therefore, all of the method calls that you can do on classes derived from Object fail. I'm not as familiar with C#'s introspection capabilities, so I'm afraid that I can't give you specific advice on how to fix it.

Matt
Incorrect. Int's, Bool's, and Double's are objects. Look at the object browser to prove it...
Jason Punyon
int, double and bool should map to the structs System.Int32, System.Double, and System.Boolean respectively.
R. Bemrose
+6  A: 

I guess the problem is that x => Property1 expression contains implicit cast to object. Compiler adds such cast to fulfil arguments of GetPropertyName.

You should check for this cast

private string GetPropertyName(Expression<Func<object, object>> f) {
    var body = f.Body;
    if (body.NodeType==ExpressionType.Convert)
      body = ((UnaryExpression) body).Operand;
    if ((body as MemberExpression) != null) {
        return (body as MemberExpression).Member.Name;
    }
    return "";
}
Denis Krjuchkov
thanks. This is really what I was looking for.
Jronny
+2  A: 

There is a boxing operation happening under the covers: The int is boxed in order to pass as an object.

To avoid further problems, I'd recommend changing the signature of your method and make it generic:

private string GetPropertyName<T, TResult>(Expression<Func<T, TResult>> f) {
    // ...
}

This is entirely untested but it should resolve your issue; The use of generics should avoid the necessity to box or convert anything (implicitly).

Bryan Menard