以编程方式创建属性访问器函数的集合

时间:2012-01-27 16:48:33

标签: c#

我想要做的是获取任何类类型,并为对象图中的所有属性创建一个“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
}

2 个答案:

答案 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;
}