¿Cómo obtener la PropertyInfo de una propiedad específica?

82

Quiero obtener PropertyInfo para una propiedad específica. Podría usar:

foreach(PropertyInfo p in typeof(MyObject).GetProperties())
{
    if ( p.Name == "MyProperty") { return p }
}

Pero debe haber una forma de hacer algo similar a

typeof(MyProperty) as PropertyInfo

¿Esta ahí? ¿O estoy atascado haciendo una comparación de cadenas de tipo inseguro?

Salud.

tenpn
fuente

Respuestas:

61

Puede usar el nuevo nameof()operador que forma parte de C # 6 y está disponible en Visual Studio 2015. Más información aquí .

Para su ejemplo, usaría:

PropertyInfo result = typeof(MyObject).GetProperty(nameof(MyObject.MyProperty));

El compilador se convertirá nameof(MyObject.MyProperty)en la cadena "MyProperty", pero usted obtiene el beneficio de poder refactorizar el nombre de la propiedad sin tener que recordar cambiar la cadena porque Visual Studio, ReSharper y similares saben cómo refactorizar nameof()valores.

Kevin Kalitowski
fuente
1
Podría decirse que sería un poco más claro si su ejemplo comenzara con en PropertyInfo result =lugar de var result =.
DavidRR
134

Hay una forma .NET 3.5 con lambdas / Expressionque no usa cadenas ...

using System;
using System.Linq.Expressions;
using System.Reflection;

class Foo
{
    public string Bar { get; set; }
}
static class Program
{
    static void Main()
    {
        PropertyInfo prop = PropertyHelper<Foo>.GetProperty(x => x.Bar);
    }
}
public static class PropertyHelper<T>
{
    public static PropertyInfo GetProperty<TValue>(
        Expression<Func<T, TValue>> selector)
    {
        Expression body = selector;
        if (body is LambdaExpression)
        {
            body = ((LambdaExpression)body).Body;
        }
        switch (body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (PropertyInfo)((MemberExpression)body).Member;
            default:
                throw new InvalidOperationException();
        }
    }
}
Marc Gravell
fuente
Buena solución, pero desafortunadamente no estoy usando .NET3.5. ¡Aún así, tick!
tenpn
1
En 2.0, la respuesta de Vojislav Stojkovic es lo más cercano que puedes conseguir.
Marc Gravell
4
una pregunta: ¿por qué hay una prueba en "body is LambdaExpression" antes de que extraiga la propiedad .Body? ¿No es el selector siempre una LambdaExpression?
tigrou
@tigrou posiblemente sea solo un descuido, y quizás yo tome prestado el código existente que funcionó en contra de soloExpression
Marc Gravell
@MarcGravell esta implementación no es muy sólida. No obtiene la información correcta de la propiedad en el caso de PropertyHelper<Derived>.GetProperty(x => x.BaseProperty);. Ver stackoverflow.com/questions/6658669/…
nawfal
13

Puedes hacerlo:

typeof(MyObject).GetProperty("MyProperty")

Sin embargo, dado que C # no tiene un tipo de "símbolo", no hay nada que le ayude a evitar el uso de cadenas. Por cierto, ¿por qué llamas inseguro a este tipo?

Vojislav Stojkovic
fuente
38
¿Porque no se evalúa en tiempo de compilación? Si cambiara el nombre de mi propiedad o escribiera la cadena, no lo sabría hasta que se ejecutara el código.
tenpn
1

La reflexión se utiliza para la evaluación del tipo de ejecución. Por lo tanto, sus constantes de cadena no se pueden verificar en tiempo de compilación.

Darin Dimitrov
fuente
5
Eso es lo que OP está tratando de evitar. No estoy seguro si esto responde a la pregunta.
nawfal
Un buen punto con respecto al tiempo de compilación frente al tiempo de ejecución y la intención original del OP, aunque evitar las cadenas codificadas todavía parece ser la solución más limpia: evita la posibilidad de errores tipográficos, permite una refactorización más fácil y crea un estilo de código más limpio.
Brian Sweeney