2016-07-22 112 views
0

我目前在我的程序中使用FieldInfo.GetValueFieldInfo.SetValue相当多,这大大减慢了我的程序。C#FieldInfo反射选择

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

FieldInfo的建议方法是什么?

编辑: 我跟着this useful linkCodeCaster's回复。这是一个很好的搜索方向。

现在,我没有得到这个答案的“唯一”一点是我如何缓存getters/setters并以通用的方式重新使用它们,只使用字段的名称 - 基本上是什么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.... 
+0

不使用反射,除非你绝对需要它。 – CodeCaster

+0

FieldInfo是如何获得的?如果您在编译期间知道该字段的名称,我建议为set设置一对lambda表达式并获取该值。 – IllidanS4

+1

@CodeCaster不是重复的,至少不是链接的问题。请注意,链接中的问题与PropertyInfo有关,这是一个关于FieldInfo的问题。这两者之间存在显着差异。 – IllidanS4

回答

1

您可以使用Expression s来生成更快的字段存取器。如果您希望他们使用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); 
+0

我试着编译你的例子。它看起来类型从静态只读字段中丢失。我尝试使用“Expression”,但是然后编译器无法使用这些参数解析对Expression.Lambda()的调用。好。所以“ParameterExpression”就是需要的。 –

+0

谢谢,@DarrelLee。我从RoslynPad复制了代码,然后意识到我可以通过将参数拉到静态字段并将其忘记类型来优化它:) –

+0

还必须添加专用集合;为“获取”和“设置”。或者是新的C#6.0语法?隐含的私人设置? –