1

I'm trying to implement static reflection for all fields in the class. In other words, I have to create get and set using name for all these fields.

I use the answers on Set field value with Expression tree, and came to the following solution

  public class ExpressionSetterGetter
    {
        public class SetterGetter<T> where T : class
        {
            public Delegate getter;
            public Action<T, object> setter;
        }

        public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>() where T : class
        {

            var dic = new Dictionary<string, SetterGetter<T>>();
            SetterGetter<T> setterGetter;

            var type = typeof(T);
            var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            foreach (var fieldInfo in fields)
            {
                var targetExp = Expression.Parameter(type, "target");
                var valueExp = Expression.Parameter(typeof(object), "value");
                var fieldExp = Expression.Field(targetExp, fieldInfo);
                var assignExp = Expression.Assign(fieldExp, Expression.Convert(valueExp, fieldExp.Type));
                var fieldSetter = Expression.Lambda<Action<T, object>>(assignExp, targetExp, valueExp).Compile();

                ParameterExpression objParm = Expression.Parameter(type, "obj");
                MemberExpression fieldExpr = Expression.Field(objParm, fieldInfo.Name);
                var fieldExprConverted = Expression.Convert(fieldExpr, typeof(object));
                var fieldGetter = Expression.Lambda(fieldExprConverted, objParm).Compile();

                setterGetter = new SetterGetter<T>() { setter = fieldSetter, getter = fieldGetter };

                dic.Add(fieldInfo.Name, setterGetter);
            }
            return dic;
        }
    }

Now, I have these two issues.

  1. I use type.GetFields(), but MSDN says it is a reflection method. What means that the compiler doesn't know the type before runtime. Am I right? If it is correct, what is the reason to use the expression trees. As far as I know expression trees translate to the code at compile-time time, what means almost no additional costs.

  2. The same logic. What if I put as a parameter a list with name of fields what have to be wrapped. In other words, instead of type.GetFields() I simply put the names of fields as parameters.

    public static Dictionary<string, SetterGetter<T>> GetFieldSetterGetterExpressions<T>(IEnumerable<string> fieldNames)

Obviously, the list can be not known at compile-time. Again, how the CLR will react?

Community
  • 1
  • 1
Simon S
  • 19
  • 5
  • The CLR does not know what an expression tree is. That's just a library that anyone can write. – usr Aug 17 '16 at 15:00

1 Answers1

1
  1. Expression trees' output is not known in compile time, they are compiled at runtime, which is something different. Advantage of using (cached) expression trees compilation is that reflection heavy lifting is performed only once, during the expression construction and compilation. From there, invocation of the resulting delegate is very fast.
  2. In case you are sure the list specifies only the fields that actually exist in your class and you provide only a subset of all the fields, you could, in theory, somewhat reduce the performance impact of the reflection. But you should keep in mind that you will still need the FieldInfo instances for each of them which could only be retrieved using reflection. So the overall price of invoking GetField for every known field will probably be even higher than just calling GetFields for all of them.

The easiest way to set fields value in compile time is converting your private fields to public properties. Then, you can set them as you wish.

And this is not a joke on you, it's an explanation of the difference - C# doesn't allow setting fields from outside, except using reflection API's. And those API's designed for runtime, not for compile time.

If you'd like to bend the rules and produce such a code at compilation time (precisely, at post-compilation time), you should use some third party library such as PostSharp or Fody.

And that's the end of the story, so long as you are using C# in it's current or one of the previous versions.

galenus
  • 2,087
  • 16
  • 24
  • Thank you for your answer. Do you know a book where can I read how to build expressions and (maybe) other functional things in c#? Although it is still much more better than reflection, I have to ask about possibilities to do it in compilation time. Assume I know everything about the class, and for example I want to have the dynamic delegates for all open fields as above. What is a reason for the compiler to not do it in compile time? Is there a CLR restriction or some logic behind it? – Simon S Aug 17 '16 at 14:03
  • @SimonS I added more explanation to my answer – galenus Aug 17 '16 at 14:28