2016-07-22 13 views
0

В настоящее время я использую FieldInfo.GetValue и FieldInfo.SetValue в моей программе, что значительно замедляет мою программу.C# FieldInfo отражение альтернативы

Для PropertyInfo Я использую методы GetValueGetter и GetValueSetter, поэтому я использую только одно отражение для определенного типа. Для FieldInfo методы не существуют.

Что такое предлагаемый подход для FieldInfo?

EDIT: Я следовал this useful link от CodeCaster's ответ. Это отличное направление поиска.

Теперь «единственная» точка, которую я не получаю в этом ответе, заключается в том, как я могу кэшировать геттеры/сеттеры и повторно использовать их в общем виде, используя только имя поля - это в основном то, что 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? Если вы знаете имя поля во время компиляции, я предлагаю сделать пару лямбда-выражения для набора и получить значение. – IllidanS4

+1

@CodeCaster Не дубликат, по крайней мере, не связанный вопрос. Обратите внимание, что вопрос в ссылке связан с PropertyInfo, а именно с полем FieldInfo. В этих двух существенных различиях. – IllidanS4

ответ

1

Вы можете использовать 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); 
+0

Я попытался скомпилировать ваш пример. Кажется, что типы отсутствуют в статических полях readonly. Я попытался использовать «Expression», но тогда компилятор не смог разрешить вызов Expression.Lambda() с этими параметрами. ОК. Поэтому «ParameterExpression» - это то, что необходимо. –

+0

Спасибо, @DarrelLee. Я скопировал код из RoslynPad, а затем понял, что могу немного его оптимизировать, потянув параметры на статические поля и забыл тип :) –

+0

Также пришлось добавить частный набор; для «Получить» и «Установить». Или это новый синтаксис C# 6.0? Подразумевается частный набор? –