using System; using System.Reflection; using System.Reflection.Emit; using System.Linq.Expressions; namespace Svelto.Utilities { //https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-sharp-expression-tree/321686#321686 public static class FastInvoke where T : class { #if ENABLE_IL2CPP public static Action MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false) { return new Action((target, value) => field.SetValue(target, value)); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #elif !NETFX_CORE public static CastedAction MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(object) }); ILGenerator cg = m.GetILGenerator(); // arg0. = arg1 cg.Emit(OpCodes.Ldarg_0); cg.Emit(OpCodes.Ldarg_1); cg.Emit(OpCodes.Stfld, field); cg.Emit(OpCodes.Ret); var del = m.CreateDelegate(typeof(Action)); return new CastedAction(del); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #else public static CastedAction MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { ParameterExpression targetExp = Expression.Parameter(typeof(T), "target"); ParameterExpression valueExp = Expression.Parameter(typeof(object), "value"); MemberExpression fieldExp = Expression.Field(targetExp, field); UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType); BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp); Type type = typeof(Action<,>).MakeGenericType(new Type[] { typeof(T), typeof(object) }); var setter = Expression.Lambda(type, assignExp, targetExp, valueExp).Compile(); return new CastedAction(setter); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #endif } public abstract class CastedAction { abstract public void Call(W target, object value); } public class CastedAction : CastedAction where W : class where T:class { Action setter; public CastedAction(Delegate setter) { this.setter = (Action)setter; } override public void Call(W target, object value) { setter(target as T, value); } } }