Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FastInvoke.cs 3.3KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. using System;
  2. using System.Reflection;
  3. using System.Reflection.Emit;
  4. using System.Linq.Expressions;
  5. namespace Svelto.Utilities
  6. {
  7. //https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-sharp-expression-tree/321686#321686
  8. public static class FastInvoke<T> where T : class
  9. {
  10. #if ENABLE_IL2CPP
  11. public static Action<CastedType, object> MakeSetter<CastedType>(FieldInfo field) where CastedType:class
  12. {
  13. if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false)
  14. {
  15. return new Action<CastedType, object>((target, value) => field.SetValue(target, value));
  16. }
  17. throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported EntityView field (must be an interface and a class)");
  18. }
  19. #elif !NETFX_CORE
  20. public static CastedAction<CastedType> MakeSetter<CastedType>(FieldInfo field) where CastedType:class
  21. {
  22. if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false)
  23. {
  24. DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(object) });
  25. ILGenerator cg = m.GetILGenerator();
  26. // arg0.<field> = arg1
  27. cg.Emit(OpCodes.Ldarg_0);
  28. cg.Emit(OpCodes.Ldarg_1);
  29. cg.Emit(OpCodes.Stfld, field);
  30. cg.Emit(OpCodes.Ret);
  31. var del = m.CreateDelegate(typeof(Action<T, object>));
  32. return new CastedAction<CastedType, T>(del);
  33. }
  34. throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported EntityView field (must be an interface and a class)");
  35. }
  36. #else
  37. public static CastedAction<CastedType> MakeSetter<CastedType>(FieldInfo field) where CastedType:class
  38. {
  39. if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false)
  40. {
  41. ParameterExpression targetExp = Expression.Parameter(typeof(T), "target");
  42. ParameterExpression valueExp = Expression.Parameter(typeof(object), "value");
  43. MemberExpression fieldExp = Expression.Field(targetExp, field);
  44. UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType);
  45. BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp);
  46. Type type = typeof(Action<,>).MakeGenericType(new Type[] { typeof(T), typeof(object) });
  47. var setter = Expression.Lambda(type, assignExp, targetExp, valueExp).Compile();
  48. return new CastedAction<CastedType, T>(setter);
  49. }
  50. throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported EntityView field (must be an interface and a class)");
  51. }
  52. #endif
  53. }
  54. public abstract class CastedAction<W>
  55. {
  56. abstract public void Call(W target, object value);
  57. }
  58. public class CastedAction<W, T> : CastedAction<W> where W : class where T:class
  59. {
  60. Action<T, object> setter;
  61. public CastedAction(Delegate setter)
  62. {
  63. this.setter = (Action<T, object>)setter;
  64. }
  65. override public void Call(W target, object value)
  66. {
  67. setter(target as T, value);
  68. }
  69. }
  70. }