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

cac*_*ce7 4 c#

我想要做的是获取任何类类型,并为对象图中的所有属性创建一个"获取"访问器列表.

集合的确切格式,顺序等并不重要,我只是不知道如何开始识别和创建所有属性的访问器.它可能采取以下形式:

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
}
Run Code Online (Sandbox Code Playgroud)

Ani*_*Ani 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();
Run Code Online (Sandbox Code Playgroud)

请注意,尽管Delegate.CreateDelegate看起来是一个明显的选择,但是在装箱值类型属性时会遇到一些问题.表达树优雅地躲避这个问题.

请注意,您还需要一些工作才能获得"嵌套"属性,但希望我已经给予ypu足以让您入门(提示:recurse).最后一个指针:注意对象图中的循环!