1

I am currently using FieldInfo.GetValue and FieldInfo.SetValue quite a lot in my programm, which is significantly slowing up my programm.

For PropertyInfo I use the GetValueGetter and GetValueSetter methods so I only use reflection once for a given type. For the FieldInfo, the methods don't exist.

What is the suggested approach for FieldInfo?

EDIT: I followed this useful link from CodeCaster's reply. This is a great search direction.

Now the "only" point that I don't get in this answer is how I can cache the getters / setters and re-use them in a generic way, using only the field's name - which is basically what the SetValue is doing

// generate the cache
Dictionary<string, object> setters = new Dictionary<string, object>();
Type t = this.GetType();
foreach (FieldInfo fld in t.GetFields()) {
     MethodInfo method = t.GetMethod("CreateSetter");
     MethodInfo genericMethod = method.MakeGenericMethod( new Type[] {this.GetType(), fld.FieldType});
     setters.Add(fld.Name, genericMethod.Invoke(null, new[] {fld}));
}
// now how would I use these setters?
setters[fld.Name].Invoke(this, new object[] {newValue}); // => doesn't work without cast....
Community
  • 1
  • 1
neggenbe
  • 1,697
  • 2
  • 24
  • 62
  • Not using reflection unless you absolutely need it. – CodeCaster Jul 22 '16 at 14:12
  • How is the FieldInfo obtained? If you know the name of the field during compile-time, I suggest making a pair of lambda expression for set and get the value. – IS4 Jul 22 '16 at 14:13
  • 1
    @CodeCaster Not a duplicate, at least not of the linked question. Please note that the question in link is about PropertyInfo, this one about FieldInfo. There's a significant difference in these two. – IS4 Jul 22 '16 at 14:18
  • 3
    @Illidan that doesn't matter, the discussion is still the same. Cache the Property|FieldInfo objects, use Reflection.Emit to actually emit the IL that assigns the fields instead of going the reflection way (or use a library that does so) and so on, all of which the OP can use to do further research. See also [Is there a way to create a delegate to get and set values for a FieldInfo?](http://stackoverflow.com/questions/16073091/). Enough has been written on this subject already, and one can only select one duplicate. This question is in no way unique, nor well-researched. – CodeCaster Jul 22 '16 at 14:19
  • 1
    @CodeCaster That's a much better link to help the questioner, thanks. – IS4 Jul 22 '16 at 14:22
  • instead of us trying to guess what will make things faster you should explain to us why you need to use reflection? – johnny 5 Jul 23 '16 at 05:13

1 Answers1

1

You could use Expressions to generate faster field accessors. If you want them to work on Object rather than the field's concrete type, you'd have to add casts (Convert) in the expression.

using System.Linq.Expressions;

class FieldAccessor
{
    private static readonly ParameterExpression fieldParameter = Expression.Parameter(typeof(object));
    private static readonly ParameterExpression ownerParameter = Expression.Parameter(typeof(object));

    public FieldAccessor(Type type, string fieldName)
    {
        var field = type.GetField(fieldName,
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        if (field == null) throw new ArgumentException();

        var fieldExpression = Expression.Field(
            Expression.Convert(ownerParameter, type), field);

        Get = Expression.Lambda<Func<object, object>>(
            Expression.Convert(fieldExpression, typeof(object)),
            ownerParameter).Compile();

        Set = Expression.Lambda<Action<object, object>>(
            Expression.Assign(fieldExpression,
                Expression.Convert(fieldParameter, field.FieldType)), 
            ownerParameter, fieldParameter).Compile();
    }

    public Func<object, object> Get { get; }

    public Action<object, object> Set { get; }
}

Usage:

class M
{
    private string s;
}

var accessors = new Dictionary<string, FieldAccessor>();

// expensive - you should do this only once
accessors.Add("s", new FieldAccessor(typeof(M), "s"));

var m = new M();
accessors["s"].Set(m, "Foo");
var value = accessors["s"].Get(m);
Darrel Lee
  • 2,372
  • 22
  • 22
Eli Arbel
  • 22,391
  • 3
  • 45
  • 71
  • I tried to compile your example. It appears the types are missing from the static readonly fields. I tried to use "Expression", but then the compiler could not resolve the call to Expression.Lambda() with those parameters. OK. So "ParameterExpression" is what is needed. – Darrel Lee Jul 23 '16 at 06:24
  • Also had to add private set; for "Get" and "Set". Or is that a new C# 6.0 syntax? Implied private set? – Darrel Lee Jul 23 '16 at 07:10