using System; using System.Linq; using System.Reflection; using UnityEngine; using Object = UnityEngine.Object; namespace SerializableFunc { [Serializable] public class SerializableAction { [SerializeField] private Object targetObject; [SerializeField] private string methodName; private Action cachedAction; private static readonly BindingFlags SuitableMethodsFlags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance; public Object TargetObject { get => targetObject; set => targetObject = value; } public string MethodName { get => methodName; set => methodName = value; } private Action GetAction() { if (targetObject == null || string.IsNullOrWhiteSpace(methodName)) return null; if (cachedAction == null) { MethodInfo info = targetObject .GetType() .GetMethods(SuitableMethodsFlags) .FirstOrDefault(IsTargetMethodInfo); if (info == null) { throw new MissingMethodException( $"Object \"{targetObject.name}\" is missing target void method: {methodName}" ); } cachedAction = (Action)Delegate.CreateDelegate(typeof(Action), targetObject, methodName); } return cachedAction; } private bool IsTargetMethodInfo(MethodInfo methodInfo) { if (!string.Equals(methodInfo.Name, methodName, StringComparison.InvariantCulture)) return false; if (methodInfo.ReturnType != typeof(void)) return false; // Only allow parameterless void methods for this version if (methodInfo.GetParameters().Length != 0) return false; return true; } public void Invoke() { GetAction()?.Invoke(); } public static implicit operator Action(SerializableAction serializableAction) { return serializableAction?.GetAction(); } } }