//#define ENABLE_IL2CPP using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using UnityEngine; namespace RosettaUI { public static class PropertyOrFieldGetterSetter { static readonly Dictionary, Func)> Table = new Dictionary, Func)>(); public static (Func, Func) GetGetterSetter(string propertyOrFieldName) { if (!Table.TryGetValue(propertyOrFieldName, out var pair)) { #if ENABLE_IL2CPP var getter = IL2CPP.PropertyOrFieldGetterSetter_IL2CPP.CreateGetter(propertyOrFieldName); var setter = IL2CPP.PropertyOrFieldGetterSetter_IL2CPP.CreateSetter(propertyOrFieldName); #else var getter = CreateGetter(propertyOrFieldName); var setter = CreateSetter(propertyOrFieldName); #endif Table[propertyOrFieldName] = pair = (getter, setter); } return pair; } // Expression.PropertyOrField is not use because it is not case sensitive static MemberExpression PropertyOrField(Expression expression, string propertyOrFieldName) { var memberInfo = TypeUtility.GetMemberInfo(expression.Type, propertyOrFieldName); return memberInfo switch { FieldInfo fi => Expression.Field(expression, fi), PropertyInfo pi => Expression.Property(expression, pi), _ => throw new ArgumentException($"{expression.Type} does not have a member '{propertyOrFieldName}'", nameof(propertyOrFieldName)) }; } // Getter // Base Code: // return obj.propertyOrFieldName; static Func CreateGetter(string propertyOrFieldName) { var objParam = Expression.Parameter(typeof(TParent)); return Expression.Lambda>(PropertyOrField(objParam, propertyOrFieldName), objParam).Compile(); } // Setter // Base Code: // obj.propertyOrFieldName = setterParam; // return obj; static Func CreateSetter(string propertyOrFieldName) { var objParam = Expression.Parameter(typeof(TParent)); var setterValueParam = Expression.Parameter(typeof(TValue)); var returnTarget = Expression.Label(typeof(TParent)); BlockExpression block = null; try { block = Expression.Block( typeof(TParent), Expression.Assign(PropertyOrField(objParam, propertyOrFieldName), setterValueParam), Expression.Return(returnTarget, objParam), Expression.Label(returnTarget, Expression.Default(typeof(TParent))) ); } catch (Exception e) { Debug.LogError($"{typeof(PropertyOrFieldGetterSetter)}.{nameof(CreateSetter)} propertyOrFieldName[{propertyOrFieldName}]\n{e}"); } return Expression.Lambda>(block, objParam, setterValueParam).Compile(); } } }