C# 以编程方式创建属性访问器函数的集合
我想做的是获取任何类类型并创建一个对象图中所有属性的“get”访问器列表 集合的确切格式、顺序等并不重要,我只是不知道如何开始识别和创建所有属性的访问器。它可能采取如下形式:C# 以编程方式创建属性访问器函数的集合,c#,C#,我想做的是获取任何类类型并创建一个对象图中所有属性的“get”访问器列表 集合的确切格式、顺序等并不重要,我只是不知道如何开始识别和创建所有属性的访问器。它可能采取如下形式: public static List<Func<T,object>> CreateAccessors<T>() { Type t = typeof(T); // Identify all properties and properties of properties (etc
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
}
公共静态列表CreateAccessors()
{
类型t=类型(t);
//确定T的所有属性和属性(等)的属性
//返回lambda函数列表,以访问给定T实例的每个函数
}
公共无效MyTest()
{
MyClass对象1;
var accessors=CreateAccessors();
var myVal1=accessors[0](object1);
var myVal2=访问器[1](object1);
//myVal1现在可能包含object1.Property1的值
//myVal2现在可能包含object1.Property4.ThirdValue.Alpha的值
}
公共静态列表CreateAccessors()
{
var访问器=新列表();
类型t=类型(t);
foreach(t.GetProperties(BindingFlags.Instance | BindingFlags.Public)中的PropertyInfo属性){
如果(道具可阅读){
var p=道具;
Add(x=>p.GetValue(x,null));
}
}
返回访问器;
}
编辑: 这里有一个变量,它返回编译后的表达式,应该比使用反射的前一个变量快得多
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;
}
公共静态列表CreateAccessorsCompiled()
{
var访问器=新列表();
类型t=类型(t);
foreach(t.GetProperties(BindingFlags.Instance | BindingFlags.Public)中的PropertyInfo属性){
如果(道具可阅读){
ParameterExpression lambdaParam=Expression.Parameter(t,“实例”);
表达体表达;
MemberExpression memberAccessExpression=Expression.MakeMemberAccess(Expression.Convert(lambdaParam,t),prop);
if(prop.PropertyType==typeof(object)){//Create lambda expression:(instance)=>((T)instance).Member
bodyExpression=memberAccessExpression;
}else{//创建lambda表达式:(实例)=>(对象)((T)实例).Member
bodyExpression=Expression.Convert(memberAccessExpression,typeof(object));
}
var lambda=Expression.lambda(bodyExpression,lambdaParam);
Add(lambda.Compile());
}
}
返回访问器;
}
您可以使用反射来提取属性和表达式树,以帮助构建以属性获取程序为目标的委托:
// 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();
//从类型为的所有公共实例属性开始
var accessors=type.GetProperties中的from属性
(BindingFlags.Instance | BindingFlags.Public)
//属性必须可读
where property.CanRead
//组装表单的表达式树:
//foo=>(对象)foo.Property
//福
let parameter=Expression.parameter(类型“foo”)
//食物财产
让propertyEx=Expression.Property(参数,属性)
//(object)foo.Property-我们需要此转换
//因为属性可能是值类型。
let body=Expression.Convert(propertyEx,typeof(object))
//foo=>(对象)foo.Property
设expr=Expression.Lambda(主体,参数)
//将树编译为Func委托
选择expr.Compile();
返回访问器。ToList();
请注意,尽管Delegate.CreateDelegate
似乎是一个明显的选择,但装箱值类型属性时会遇到一些问题。表达式树巧妙地回避了这个问题
请注意,您还需要做更多的工作才能获得“嵌套”属性,但希望我已经提供了足够的ypu让您开始(提示:recurse)。最后一点:注意对象图中的循环 看一看Jon Skeet的这篇博文-,除了递归之外,它几乎都在那里。你可能想看到Jon的MVP博客也不见了,这是他(个人?)博客上的一篇博文:另一个需要注意的是嵌套对象中的
null
。如果b
为空,您希望a.b.c
返回什么?谢谢您的回复,@Ani。不过,递归部分对我来说最麻烦。我是表达式树的新手,不太了解如何递归,因此我正在构建能够访问更深层属性的表达式。你有更多信息的例子或链接吗?另外,在这种情况下,有些属性可能是索引数组。我如何解决这个问题?let
?这是C#。。。?
// 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();