Как получить PropertyInfo определенного свойства?

82

Я хочу получить PropertyInfo для определенного свойства. Я мог бы использовать:

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

Но должен быть способ сделать что-то похожее на

typeof(MyProperty) as PropertyInfo

Здесь? Или я застрял в сравнении строк с небезопасным типом?

Ура.

tenpn
источник

Ответы:

61

Вы можете использовать новый nameof()оператор, который является частью C # 6 и доступен в Visual Studio 2015. Подробнее здесь .

В вашем примере вы должны использовать:

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

Компилятор преобразует nameof(MyObject.MyProperty)в строку «MyProperty», но вы получаете преимущество, заключающееся в возможности рефакторинга имени свойства без необходимости помнить об изменении строки, потому что Visual Studio, ReSharper и т.п. умеют рефакторинг nameof()значений.

Кевин Калитовски
источник
1
Было бы, возможно, немного яснее, если бы ваш пример начинался с PropertyInfo result =вместо var result =.
DavidRR
134

Существует способ .NET 3.5 с лямбдами / Expression, который не использует строки ...

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();
        }
    }
}
Марк Гравелл
источник
Хорошее решение, но, к сожалению, я не использую .NET3.5. Тем не менее, отметьте!
tenpn
1
В версии 2.0 ответ Воислава Стойковича - самый близкий из возможных.
Марк Гравелл
4
один вопрос: почему есть тест на "body is LambdaExpression" перед извлечением свойства .Body? Разве селектор не всегда является LambdaExpression?
tigrou
@tigrou вполне возможно, просто недосмотр, и, возможно, я позаимствовал существующий код, который работал против всегоExpression
Марк Гравелл
@MarcGravell, эта реализация не очень звуковая. Вы не получите правильную информацию об объекте размещения в случае PropertyHelper<Derived>.GetProperty(x => x.BaseProperty);. См stackoverflow.com/questions/6658669/...
Навфал
13

Ты можешь это сделать:

typeof(MyObject).GetProperty("MyProperty")

Однако, поскольку C # не имеет «символьного» типа, ничто не поможет вам избежать использования строки. Кстати, почему вы называете это типо-небезопасным?

Воислав Стойкович
источник
38
Потому что он не оценивается во время компиляции? Если бы я изменил имя своего свойства или опечатал строку, я бы не узнал, пока не запустится код.
tenpn
1

Отражение используется для оценки типа среды выполнения. Таким образом, ваши строковые константы не могут быть проверены во время компиляции.

Дарин Димитров
источник
5
Это то, чего OP пытается избежать. Не уверен, что это ответ на вопрос.
nawfal
Хороший момент относительно времени компиляции и времени выполнения и первоначального намерения OP, хотя отказ от жестко запрограммированных строк по-прежнему кажется самым чистым решением - избегает возможности опечаток, позволяет упростить рефакторинг и делает стиль кода более чистым.
Брайан Суини