Як отримати PropertyInfo конкретного майна?


82

Я хочу отримати PropertyInfo для певної властивості. Я міг би використати:

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

Але повинен бути спосіб зробити щось подібне

typeof(MyProperty) as PropertyInfo

Є там? Або я застряг у порівнянні рядків із небезпечним для типу?

Ура.

Відповіді:


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. Не впевнений, чи відповідає це питання.
navfal

Хороший момент щодо часу компіляції порівняно з часом виконання та початковим наміром OP, хоча уникнення жорстко закодованих рядків, як і раніше, є найчистішим рішенням - уникає можливості помилок, дозволяє спростити рефакторинг та робить більш чистим стиль коду.
Brian Sweeney
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.