C# FieldInfo 反射替代方案 [英] C# FieldInfo reflection alternatives

查看:58
本文介绍了C# FieldInfo 反射替代方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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.

FieldInfo 的建议方法是什么?

我跟着 这个有用的链接来自CodeCaster的回复.这是一个很好的搜索方向.

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

现在我在这个答案中没有得到的唯一"点是我如何缓存 getter/setter 并以通用方式重新使用它们,只使用字段的名称 - 这基本上是 SetValue 在做什么

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

推荐答案

您可以使用 Expression 来生成更快的字段访问器.如果您希望它们处理 Object 而不是字段的具体类型,则必须在表达式中添加强制转换 (Convert).

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

用法:

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

这篇关于C# FieldInfo 反射替代方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆