C# FieldInfo 反射替代方案 [英] C# FieldInfo reflection alternatives
问题描述
我目前在我的程序中大量使用 FieldInfo.GetValue
和 FieldInfo.SetValue
,这大大减慢了我的程序速度.
I am currently using FieldInfo.GetValue
and FieldInfo.SetValue
quite a lot in my programm, which is significantly slowing up my programm.
对于 PropertyInfo
,我使用 GetValueGetter
和 GetValueSetter
方法,所以我只对给定类型使用反射一次.对于 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 Expression
s 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屋!