给定属性名称,如何创建委托以获取其值

时间:2010-10-21 15:18:39

标签: c# reflection delegates

我们有一些代码,给定属性名称使用反射来实现Comparer。

我希望存储一个委托/ Func来获取值,而不是每次我们需要获取值时支付反映价格。

鉴于这样的课程:

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 proerty,它会抛出一个带有“绑定到目标方法的错误”消息的ArgumentException

我错过了什么?还有其他办法吗?

2 个答案:

答案 0 :(得分:8)

您在编译时知道声明类型但不知道属性类型似乎很奇怪。总之...

您需要额外的步骤将属性值转换为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 :(得分:1)

可能是因为Age基本上被定义为:

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");