Programmatically create collections of object access functions

What I want to do is take any type of class and create a "get" list for all the properties in the object graph.

Exact format, order, etc. The collection doesn’t matter, I just don’t quite know how to start identifying and creating accessories for all the properties. It might look like this:

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 } 
+4
source share
2 answers

You can use reflection to extract properties and expression trees to help assemble delegates targeting getters properties:

  // 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(); 

Note that although Delegate.CreateDelegate seems like an obvious choice, you will have some problems with properties like boxing. Trees express this problem elegantly.

Note that you will need one more job to be able to “nested” properties, but I hope I gave ypu enough to get you started (hint: recurse). One final pointer with this: keep track of the loops in the object graph!

+5
source
 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; } 

EDIT:

Here is an option that returns compiled expressions and should be much faster than the previous one using reflection

 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; } 
0
source

Source: https://habr.com/ru/post/1393396/


All Articles