C#字段信息反射备选方案

本文关键字:方案 反射 字段 信息 | 更新日期: 2023-09-27 17:58:10

我目前在程序中大量使用FieldInfo.GetValueFieldInfo.SetValue,这大大降低了我的程序速度。

对于PropertyInfo,我使用GetValueGetterGetValueSetter方法,所以对于给定的类型,我只使用反射一次。对于FieldInfo,这些方法不存在。

FieldInfo的建议方法是什么?

编辑:我关注了CodeCaster回复中的这个有用链接。这是一个很好的搜索方向。

现在,我在这个答案中没有得到的"唯一"一点是,我如何缓存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....

C#字段信息反射备选方案

您可以使用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; }
}

用法:

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