mercredi 21 octobre 2020

Reflection to expression tree: passing a parameter and accessing a field on a static class, but with an expression tree

For performance reasons, we're trying to refactor one our routines from reflection to expression trees. We've already made the necessary calculations and concluded this change will benefit our userbase.

Sadly though we're struggling with what seemed like trivial matters... at first: using a dynamic field name, and returning values in expression trees. There's multiple generic, 'hardwired' examples around for these, but we haven't found decent leads on proper real use cases for us.

Basically we have the following two objects (slightly adapted for posting convenience)

        public struct clsAlterRowTableObject
        {
           public string propActor { get; set; }
           public string propIdColumnName { get; set; }
        }

        public static class clsAlterRowTableManager
        {
            public static clsAlterRowTableObject table1 = new clsAlterRowTableManager.clsAlterRowTableObject
            {
                 propActor = "table1 ",
                 propIdColumnName = "table1Id"
            };

            public static clsAlterRowTableObject table2 = new clsAlterRowTableManager.clsAlterRowTableObject
            {
                 propActor = "table2",
                 propIdColumnName = "table2Id"
            };
        }

and we have the following function:

            private static clsAlterRowTableObject metGetField(string varpFieldName)
            {
                FieldInfo varManagerTableProperty = typeof(clsAlterRowTableManager).GetField(varpFieldName, BindingFlags.Public | BindingFlags.Static );
                return (clsAlterRowTableObject)varManagerTableProperty.GetValue(null);
            }

This function successfully returns the instance of the fields of the manager (table1 and table2) and currently serves our purpose. This function is potentially called thousands of times per hour.

Now our attempt and converting said function in an expression tree. Our intent is to declare a static reference to the compiled Func, and use that to perform the calls... but first we need to successfully convert the method :)

            private static Func<string, clsAlterRowTableObject> metGetTableInstance()
            {
                //parameter definition
                ParameterExpression varTableName = Expression.Parameter(typeof(string), "varpFieldName");
                BindingFlags varFlags = BindingFlags.Public | BindingFlags.Static;
                Expression varBindingFlags = Expression.Constant(varFlags);

                //return value definition
                ParameterExpression varReturnValue = Expression.Variable(typeof(clsAlterRowTableManager.clsAlterRowTableObject));
                LabelTarget varReturnTarget = Expression.Label(typeof(clsAlterRowTableObject));
                GotoExpression varReturnExpression = Expression.Return(varReturnTarget, varReturnValue, typeof(clsAlterRowTableManager.clsAlterRowTableObject));
                LabelExpression varReturnLabel = Expression.Label(varReturnTarget, Expression.Constant(new clsAlterRowTableManager.clsAlterRowTableObject { }));

                //original call
                //FieldInfo varManagerTableProperty = typeof(clsAlterRowTableManager).GetField(varpTableName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
                //return (clsAlterRowTableObject)varManagerTableProperty.GetValue(null);

                //this test works
                var varProperty = Expression.Field(null, typeof(clsAlterRowTableManager), "table1");

                //...but how can we use the actual parameter for the field name
                var varProperty = Expression.Field(null, typeof(clsAlterRowTableManager), ???somethingsomethingvarpFieldName???);
                //...more statements with expressions list, block and compile, to be focused on later

So here's the problem: with one single google search you can immediately find examples on how to retrieve a field by a constant name, but there's a lack of examples on how to use an actual parameter as a value. Additionally, a similar problem exists when trying to -return- a value... but we'll be more than happy to solve the parameter passing issue right now.

Thanks in advance.

PS this is a repost and a rewrite for a closed question. our thanks to those that commented on it.





Aucun commentaire:

Enregistrer un commentaire