Учитывая имя свойства, как я могу создать делегата, чтобы получить его значение - PullRequest
5 голосов
/ 21 октября 2010

У нас есть некоторый код, который с помощью имени свойства использует отражение для реализации Comparer.

Я бы хотел сохранить делегат / функцию для получения значения, а не платить цену отражения каждый раз, когда нам нужно получить значение.

Учитывая класс как это:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Я пытался написать функцию, которая создала бы для меня делегат

Func<T, object> CreateGetFuncFor<T>(string propertyName)
{
    PropertyInfo prop = typeof(T).GetProperty(propertyName);

    return (Func<T, object>)Delegate.CreateDelegate(typeof(Func<T, object>), 
                                                    null, 
                                                    prop.GetGetMethod());
}

Следующий код отлично работает для получения имени

var person = new Person { Name = "Dave", Age = 42 };

var funcitonToGetName = CreateGetFuncFor<Person>("Name");
Console.WriteLine(funcitonToGetName(person));

var functionToGetAge = CreateGetFuncFor<Person>("Age");

но для свойства Age он генерирует ArgumentException с сообщением "Ошибка привязки к целевому методу"

Чего мне не хватает? Есть ли другой способ сделать это?

Ответы [ 2 ]

8 голосов
/ 21 октября 2010

Кажется странным, что вы знаете объявленный тип во время компиляции, но не тип свойства. Во всяком случае ...

Вам потребуется дополнительный шаг для преобразования значения свойства в object, чтобы оно соответствовало типу возврата делегата Func<T,object>. (Дополнительный шаг не является строго обязательным для свойств ссылочного типа, но не приносит никакого вреда.)

Func<T, object> CreateGetFuncFor<T>(string propertyName)
{
    var parameter = Expression.Parameter(typeof(T), "obj");
    var property = Expression.Property(parameter, propertyName);
    var convert = Expression.Convert(property, typeof(object));
    var lambda = Expression.Lambda(typeof(Func<T, object>), convert, parameter);

    return (Func<T, object>)lambda.Compile();
}
1 голос
/ 21 октября 2010

Это, вероятно, потому что возраст по существу определяется как:

public int Age {get; private set;}

и метод, возвращающий int, неявно не конвертируется в метод, возвращающий object, тогда как String равен.

попробовать:

Func<T, R> CreateGetFuncFor<T, R>(string propertyName)
{
    PropertyInfo prop = typeof(T).GetProperty(propertyName);
    return (Func<T, R>)Delegate.CreateDelegate(typeof(Func<T, R>), 
                                                    null, 
                                                    prop.GetGetMethod());
}

, а затем

var functionToGetAge = CreateGetFuncFor<Person, int>("Age");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...