mercredi 30 octobre 2019

Problem creating a cache for setting fields using reflection

I am trying to set a large number of fields in an object using reflection. This is fine, no worries with that, however reflection is costly and after reading many articles trying to speed this up, I am now trying to create a cache, this works fine for string variables, but for some reason it is not setting integers correctly.

All of the fields look something like this

public string MyStringField = string.Empty;
public int MyIntField = 0;
public bool MyBoolField = false;

The cache is simply a dictionary of the field name and an action delegate to do the Set.

public static Dictionary<string, Action<SettingsClass, object>> ObjectCache;

The initial population of the cache is done using the below code

var obj = new SettingsClass();
Type demoType = obj.GetType();

ObjectCache = new Dictionary<string, Action<SettingsClass, object>>();

foreach (FieldInfo item in demoType.GetFields())
{
    Type propType = item.FieldType;
    var setValue = CreateSetter<SettingsClass, object>(item);
    ObjectCache.Add(item.Name, setValue);
}

The CreateSetter method I am using to create the delegate is this - this bit I do not really understand to be honest.

private static Action<S, T> CreateSetter<S, T>(FieldInfo field)
{
string methodName = field.ReflectedType.FullName + ".set_" + field.Name;
DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2] { typeof(S), typeof(T) }, true);
ILGenerator gen = setterMethod.GetILGenerator();
   if (field.IsStatic)
   {
      gen.Emit(OpCodes.Ldarg_1);
      gen.Emit(OpCodes.Stsfld, field);
   }
   else
   {
      gen.Emit(OpCodes.Ldarg_0);
      gen.Emit(OpCodes.Ldarg_1);
      gen.Emit(OpCodes.Stfld, field);
   }
gen.Emit(OpCodes.Ret);
return (Action<S, T>)setterMethod.CreateDelegate(typeof(Action<S, T>));
}

And finally when I am invoking the delegate to populate an instance of my object I simply use: (item is simply a datarow)

ObjectCache[settingName].Invoke(obj, item["SettingValue"]);

This all works correctly, but when I try to set an integer e.g 12 it is setting to a strange value of 92266380. I have a attached an image of the watch window.

enter image description here

I assume the approach I will need to take is store the type of the property in the cache and somehow convert it in the delegate, but I am not sure how to do this.

Any advice is greatly appreciated and thank you in advance. If you need any more information let me know.





Aucun commentaire:

Enregistrer un commentaire