Files
Unity-Serializable-Func/Runtime/SerializableFuncBase.cs

90 lines
2.7 KiB
C#

using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace SerializableFunc.Runtime
{
[Serializable]
public abstract class SerializableFuncBase<TFuncType> where TFuncType : Delegate
{
[SerializeField] protected UnityEngine.Object targetObject;
[SerializeField] protected string methodName;
private TFuncType func;
private static BindingFlags SuitableMethodsFlags =
BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance;
public UnityEngine.Object TargetObject
{
get => targetObject;
set => targetObject = value;
}
public string MethodName
{
get => methodName;
set => methodName = value;
}
protected TFuncType GetReturnedFunc()
{
if (targetObject == null || string.IsNullOrWhiteSpace(methodName)) return null;
if (func == null)
{
Type funcType = typeof(TFuncType);
MethodInfo info = targetObject
.GetType()
.GetMethods(SuitableMethodsFlags)
.FirstOrDefault(x => IsTargetMethodInfo(x, funcType));
if (info == null)
{
throw new MissingMethodException(
$"Object \"{targetObject.name}\" is missing target method: {methodName}"
);
}
func = (TFuncType)Delegate.CreateDelegate(funcType, targetObject, methodName);
}
return func;
}
#region Utility Functions
private bool IsTargetMethodInfo(MethodInfo methodInfo, Type funcType)
{
if (!string.Equals(methodInfo.Name, methodName, StringComparison.InvariantCulture)) return false;
Type[] typeArguments = funcType.GetGenericArguments();
if (methodInfo.ReturnType != typeArguments.Last()) return false;
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length != (typeArguments.Length - 1)) return false;
for (int i = 0; i < parameters.Length; i++)
{
Type argType = typeArguments[i];
ParameterInfo parameterInfo = parameters[i];
if (argType != parameterInfo.ParameterType) return false;
}
return true;
}
#endregion
public static implicit operator TFuncType(SerializableFuncBase<TFuncType> func)
{
if (func == null) return null;
TFuncType result = func.GetReturnedFunc();
return result;
}
}
}