C#FieldInfo反射方案

C#FieldInfo反射方案,c#,reflection,fieldinfo,C#,Reflection,Fieldinfo,我目前在我的程序中大量使用FieldInfo.GetValue和FieldInfo.SetValue,这大大降低了我的程序速度 对于PropertyInfo我使用GetValueGetter和GetValueSetter方法,因此对于给定类型我只使用一次反射。对于字段信息,方法不存在 FieldInfo的建议方法是什么 编辑: 我听从了他的回答。这是一个伟大的搜索方向 现在,我在这个答案中没有得到的“唯一”点是如何缓存getter/setter,并以一种通用的方式重新使用它们,只使用字段的名称-

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

对于
PropertyInfo
我使用
GetValueGetter
GetValueSetter
方法,因此对于给定类型我只使用一次反射。对于
字段信息
,方法不存在

FieldInfo
的建议方法是什么

编辑: 我听从了他的回答。这是一个伟大的搜索方向

现在,我在这个答案中没有得到的“唯一”点是如何缓存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....
//生成缓存
字典设置器=新字典();
Type t=this.GetType();
foreach(t.GetFields()中的FieldInfo fld){
MethodInfo method=t.GetMethod(“CreateSetter”);
MethodInfo genericMethod=method.MakeGenericMethod(新类型[]{this.GetType(),fld.FieldType});
Add(fld.Name,genericMethod.Invoke(null,new[]{fld}));
}
//现在我该如何使用这些设置器?
setters[fld.Name].Invoke(这个,新对象[]{newValue});//=>没有演员就不行。。。。

您可以使用
Expression
s生成更快的字段访问器。如果希望它们处理
对象
而不是字段的具体类型,则必须在表达式中添加强制转换(
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; }
}
使用System.Linq.Expressions;
类字段访问器
{
私有静态只读参数Expression fieldParameter=Expression.Parameter(typeof(object));
私有静态只读参数Expression ownerParameter=Expression.Parameter(typeof(object));
公共字段访问器(类型、字符串字段名)
{
var field=type.GetField(fieldName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
如果(field==null)抛出新ArgumentException();
var fieldExpression=Expression.Field(
Expression.Convert(ownerParameter,type),字段);
Get=Expression.Lambda(
Expression.Convert(fieldExpression,typeof(object)),
ownerParameter)。编译();
Set=Expression.Lambda(
Expression.Assign(字段表达式,
Expression.Convert(fieldParameter,field.FieldType)),
ownerParameter,fieldParameter).Compile();
}
公共函数Get{Get;}
公共操作集{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);
M类
{
私有字符串;
}
var accessors=newdictionary();
//昂贵-你应该只做一次
访问器。添加(“s”,新字段访问器(类型为(M),“s”);
var m=新的m();
存取器[“s”].Set(m,“Foo”);
var值=访问器[“s”]。获取(m);

除非绝对需要,否则不要使用反射。FieldInfo是如何获得的?如果您在编译时知道字段的名称,我建议为set生成一对lambda表达式并获取值。@CodeCaster不是重复的,至少不是链接问题的重复。请注意,链接中的问题是关于PropertyInfo的,这是关于FieldInfo的。“这两者有很大的不同。”伊利丹说,没关系,讨论还是一样的。缓存属性| FieldInfo objects,使用Reflection.Emit实际发出分配字段的IL,而不是使用反射方式(或使用这样做的库)等等,OP可以使用这些方式进行进一步的研究。另见。关于这个主题已经写了足够多的文章,人们只能选择一个副本。这个问题不是唯一的,也没有经过很好的研究。@CodeCaster这是一个更好的链接来帮助提问者,谢谢。我试着编译了你的例子。静态只读字段中似乎缺少类型。我尝试使用“Expression”,但编译器无法使用这些参数解析对Expression.Lambda()的调用。好啊所以“ParameterExpression”是我们需要的。谢谢,@DarrelLee。我从RoslynPad复制了代码,然后意识到我可以通过将参数拉到静态字段来优化它,并且忘记了类型:)还必须添加私有集;用于“获取”和“设置”。或者这是一种新的C#6.0语法?暗含私密场景?@DarrelLee是的,是C#6。没有私人二传。它使用只能在构造函数中设置的支持只读字段。