简体   繁体   English

C#FieldInfo反射替代

[英]C# FieldInfo reflection alternatives

I am currently using FieldInfo.GetValue and FieldInfo.SetValue quite a lot in my programm, which is significantly slowing up my programm. 我目前在我的程序中大量使用FieldInfo.GetValueFieldInfo.SetValue ,这大大降低了我的程序速度。

For PropertyInfo I use the GetValueGetter and GetValueSetter methods so I only use reflection once for a given type. 对于PropertyInfo我使用GetValueGetterGetValueSetter方法,因此对于给定类型,我仅使用反射一次。 For the FieldInfo , the methods don't exist. 对于FieldInfo ,方法不存在。

What is the suggested approach for FieldInfo ? 建议的FieldInfo方法是什么?

EDIT: I followed this useful link from CodeCaster's reply. 编辑:我按照从CodeCaster的答复此有用的链接 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 现在,我在这个答案中没有得到的“唯一”要点是如何缓存getter / setter并以通用的方式重复使用它们,而仅使用字段名称-这基本上就是SetValue所做的

// 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....

You could use Expression s to generate faster field accessors. 您可以使用Expression生成更快的字段访问器。 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. 如果要让他们使用Object而不是字段的具体类型,则必须在表达式中添加强制类型转换( Convert )。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM