¿Cómo obtener un nombre de propiedad de un tipo dado fuertemente tipado?

.net c# expression-trees reflection

Pregunta

Me gustaría poder recuperar el nombre de una propiedad de un tipo usando una sintaxis fuertemente tipada. Ya tengo una función para obtener un nombre de propiedad de una instancia:

public static string PropertyName<T, TReturn>(this T obj, Expression<Func<T, TReturn>> property) where T : class 
{
    MemberExpression body = (MemberExpression) property.Body;
    if (body == null) throw new ArgumentException("The provided expression did not point to a property.");       
    return body.Member.Name;
}

Que se puede llamar así:

Car car = new Car();
car.PropertyName(x => x.Wheels) //returns "Wheels"

Estoy tratando de crear otra función que podría soportar lo siguiente:

Type t = Typeof(Car);
t.PropertyName(x => x.Wheels) //should return "Wheels"

O simplemente (¡incluso mejor!):

Car.PropertyName(x => x.Wheels)

¿Cómo voy a hacer esto?

Respuesta aceptada

Puedes reescribir tu método para usarlo sin crear una instancia:

var prop = ReflectionHelper.PropertyName<Car>(x => x.Wheels);

porque no usas obj dentro porque no lo necesitas:

public static class ReflectionHelper
{
    public static string PropertyName<T>(Expression<Func<T, object>> property) where T : class 
    {
        MemberExpression body = (MemberExpression)property.Body;
        return body.Member.Name;
    }
}

Tenga en cuenta que el tipo de retorno no tiene que ser fuertemente tipado, puede ser solo un object .


Respuesta popular

El ejemplo de @abatishchev solo funciona si Wheels es un tipo de referencia.

Si tienes los siguientes

public class Car
{
   public int ID;
}

Y tratas de llamar a esto

var prop = ReflectionHelper.PropertyName<Car>(x => x.ID);

Obtendrás la siguiente excepción

InvalidCastException: no se puede convertir el objeto de tipo 'System.Linq.Expressions.UnaryExpression' al tipo 'System.Linq.Expressions.MemberExpression'.

Creo que esto tiene que ver con el hecho de que está pasando un tipo de valor a la expresión, por lo que tiene que ser encuadrado en un objeto. Si pasa un tipo de referencia, no es necesario que esté encuadrado para objetar.

Lo que puedes hacer en cambio es esto:

var prop = ReflectionHelper.PropertyName((Car x) => x.Wheels);

public static class ReflectionHelper
{
    public static string PropertyName<T, P>(Expression<Func<T, P>> property) 
        where T : class 
    {
        MemberExpression body = (MemberExpression)property.Body;
        return body.Member.Name;
    }
}


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow