We have some code that given a property name uses reflection to implement a Comparer.
I would like to store a delegate/Func to get the value rather than paying the reflection price each time we need to get a value.
Given a class like this:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
I tried to write a function that would create a delegate for me
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());
}
The following code works fine for the getting the Name
var person = new Person { Name = "Dave", Age = 42 };
var funcitonToGetName = CreateGetFuncFor<Person>("Name");
Console.WriteLine(funcitonToGetName(person));
var functionToGetAge = CreateGetFuncFor<Person>("Age");
but for the Age proerty it throws an ArgumentException with the message "Error binding to target method"
What am I missing? Is there another way to do it?
It seems odd that you know the declaring type at compile-time but not the property type. Anyway...
You'll need an extra step to convert the property value to an object
so that it matches the Func<T,object>
delegate's return type. (The extra step isn't strictly necessary for reference-typed properties, but doesn't do any harm.)
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();
}
Its probably because Age is essentially defined as:
public int Age {get; private set;}
and a method returning an int
is not implicitly convertible to a method returning an object
, whereas String
is.
try:
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());
}
and then
var functionToGetAge = CreateGetFuncFor<Person, int>("Age");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With