我想要做的是获取任何类类型,并为对象图中的所有属性创建一个“get”访问器列表。
集合的确切格式,顺序等并不重要,我只是不知道如何开始识别和创建所有属性的访问器。它可能采取以下形式:
public static List<Func<T,object>> CreateAccessors<T>()
{
Type t = typeof(T);
// Identify all properties and properties of properties (etc.) of T
// Return list of lambda functions to access each one given an instance of T
}
public void MyTest()
{
MyClass object1;
var accessors = CreateAccessors<MyClass>();
var myVal1 = accessors[0](object1);
var myVal2 = accessors[1](object1);
// myVal1 might now contain the value of object1.Property1
// myVal2 might now contain the value of object1.Property4.ThirdValue.Alpha
}
答案 0 :(得分:5)
您可以使用反射来提取属性和表达式树,以帮助构建以属性getter为目标的委托:
// Start with all public instance properties of type
var accessors = from property in type.GetProperties
(BindingFlags.Instance | BindingFlags.Public)
// Property must be readable
where property.CanRead
//Assemble expression tree of the form:
// foo => (object) foo.Property
// foo
let parameter = Expression.Parameter(type, "foo")
// foo.Property
let propertyEx = Expression.Property(parameter, property)
// (object)foo.Property - We need this conversion
// because the property may be a value-type.
let body = Expression.Convert(propertyEx, typeof(object))
// foo => (object) foo.Property
let expr = Expression.Lambda<Func<T,object>>(body, parameter)
// Compile tree to Func<T,object> delegate
select expr.Compile();
return accessors.ToList();
请注意,虽然Delegate.CreateDelegate
似乎是一个明显的选择,但是在装入值类型属性时会遇到一些问题。表达树优雅地躲避这个问题。
请注意,您还需要更多工作才能获得“嵌套”属性,但希望我已经给予ypu足以让您入门(提示:recurse)。最后一个指针:注意对象图中的循环!
答案 1 :(得分:0)
public static List<Func<T, object>> CreateAccessors<T>()
{
var accessors = new List<Func<T, object>>();
Type t = typeof(T);
foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
if (prop.CanRead) {
var p = prop;
accessors.Add(x => p.GetValue(x, null));
}
}
return accessors;
}
编辑:
这是一个返回已编译表达式的变体,应该比使用反射
的前一个快得多public static List<Func<T, object>> CreateAccessorsCompiled<T>()
{
var accessors = new List<Func<T, object>>();
Type t = typeof(T);
foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
if (prop.CanRead) {
ParameterExpression lambdaParam = Expression.Parameter(t, "instance");
Expression bodyExpression;
MemberExpression memberAccessExpression = Expression.MakeMemberAccess(Expression.Convert(lambdaParam, t), prop);
if (prop.PropertyType == typeof(object)) { // Create lambda expression: (instance) => ((T)instance).Member
bodyExpression = memberAccessExpression;
} else { // Create lambda expression: (instance) => (object)((T)instance).Member
bodyExpression = Expression.Convert(memberAccessExpression, typeof(object));
}
var lambda = Expression.Lambda<Func<T, object>>(bodyExpression, lambdaParam);
accessors.Add(lambda.Compile());
}
}
return accessors;
}