Version 1.1. Generic parameters support

This commit is contained in:
Anton Zhernosek
2023-06-03 22:09:15 +02:00
parent 90b433967e
commit e7648cb9d9
13 changed files with 1022 additions and 767 deletions

3
CHANGELOG.md Normal file
View File

@@ -0,0 +1,3 @@
### 1.1.0
Added support for generic arguments. Works like a generic Func, where the last generic argument is the return type of the function. Having only the return value will look for getter properties aswell. Having > 1 generic argument will only look for suitable public methods

7
CHANGELOG.md.meta Normal file
View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4313795d52b054b409f55b7abf4be995
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a98267ecc93a89f4c9b31bad1ccb0bb0
guid: 0600072b8385f4646a65c03fada4ed7d
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 33baceefadfdeb945aa7f92e190518f0
guid: a27853cfcf7edf94fa6821cd44d52513
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -4,6 +4,8 @@ Allows you to assign Func\<T\> via the Inspector.
Looks and acts like a UnityEvent.
Supports both GUI and UI Toolkit. Tested with Unity 2020.3, 2021.3, 2022.2, 2023.1.
Tested in standalone Windows and Android builds, both with Mono and IL2CPP.
Version 1.1 supports generic parameters.
If there are no generic parameters for the func, you'll also be able to assign getter properties.
GUI Representation
![unity_inspector](https://i.imgur.com/pR4uo7H.png)
@@ -17,11 +19,15 @@ public class ExampleClass : MonoBehaviour
{
[Header("My Bool Func")]
[SerializeField] private SerializableFunc<bool> boolFunc;
[SerializeField] private SerializableFunc<int, string> stringFunc;
private void Start()
{
bool result = boolFunc.Invoke();
Debug.Log(result);
string stringResult = stringFunc.Invoke(69);
Debug.Log(stringResult);
}
}
```

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4bd647a4a04c7f947afa36dc0ab3e8bf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
using Object = UnityEngine.Object;
[System.Serializable]
public abstract class SerializableFuncBase<TFuncType>
where TFuncType : Delegate
{
[SerializeField] protected Object targetObject;
[SerializeField] protected string methodName;
private TFuncType func;
private static BindingFlags SuitableMethodsFlags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance;
protected TFuncType GetReturnedFunc()
{
if (func == null)
{
if (targetObject == null)
{
throw new ArgumentNullException("Target Object is null!");
}
if (string.IsNullOrWhiteSpace(methodName))
{
throw new ArgumentNullException("Target Method is 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;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fa96f9624fc8bad459ec0bc927427de8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a05eff3308be0b2489425421e455c65f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,175 @@
using System;
[System.Serializable]
public class SerializableFunc<TReturn> : SerializableFuncBase<Func<TReturn>>
{
public TReturn Invoke()
{
Func<TReturn> func = GetReturnedFunc();
return func();
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TReturn> : SerializableFuncBase<Func<TArg0, TReturn>>
{
public TReturn Invoke(TArg0 arg0)
{
Func<TArg0, TReturn> func = GetReturnedFunc();
return func(arg0);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1)
{
Func<TArg0, TArg1, TReturn> func = GetReturnedFunc();
return func(arg0, arg1);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2)
{
Func<TArg0, TArg1, TArg2, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3)
{
Func<TArg0, TArg1, TArg2, TArg3, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TReturn> : SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TReturn> :
SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TReturn> :
SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12, TArg13 arg13)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TReturn> :
SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12, TArg13 arg13, TArg14 arg14)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
}
}
[System.Serializable]
public class SerializableFunc<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TReturn> :
SerializableFuncBase<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TReturn>>
{
public TReturn Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12, TArg13 arg13, TArg14 arg14, TArg15 arg15)
{
Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TReturn> func = GetReturnedFunc();
return func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 638c2cd796656454f8e97e9ef2cc6ae9
guid: 37cbc0382ca8c094b869e417b3e986fe
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,73 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Utilities.SerializableData.SerializableFunc
{
[System.Serializable]
public class SerializableFunc<TReturn>
{
[SerializeField] protected Object targetObject;
[SerializeField] protected string methodName;
private Func<TReturn> func;
public Func<TReturn> Func { get { return GetReturnedFunc(); } }
public TReturn Invoke()
{
Func<TReturn> func = GetReturnedFunc();
if (func != null) return func();
return default;
}
#region Protected Interface
protected Func<TReturn> GetReturnedFunc()
{
if (func == null)
{
if (targetObject == null) return null;
if (string.IsNullOrWhiteSpace(methodName)) return null;
MethodInfo info = targetObject
.GetType()
.GetMethods(BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
.FirstOrDefault(x => IsTargetMethodInfo(x));
if (info == null) return null;
func = (Func<TReturn>)Delegate.CreateDelegate(typeof(Func<TReturn>), targetObject, methodName);
}
return func;
}
#endregion
#region Utility Functions
private bool IsTargetMethodInfo(MethodInfo x)
{
return string.Equals(x.Name, methodName, StringComparison.InvariantCultureIgnoreCase)
&& x.ReturnType == typeof(TReturn)
&& x.GetParameters().Length == 0;
}
#endregion
#region Operators
public static implicit operator Func<TReturn>(SerializableFunc<TReturn> serializableFunc)
{
if (serializableFunc == null) return null;
return serializableFunc.GetReturnedFunc();
}
#endregion
}
}