Implement TypeSearch with generics
This commit is contained in:
parent
105f461ba8
commit
25350f7036
@ -141,7 +141,7 @@ namespace MackySoft.SerializeReferenceExtensions.Editor
|
|||||||
|
|
||||||
Type baseType = ManagedReferenceUtility.GetType(managedReferenceFieldTypename);
|
Type baseType = ManagedReferenceUtility.GetType(managedReferenceFieldTypename);
|
||||||
var popup = new AdvancedTypePopup(
|
var popup = new AdvancedTypePopup(
|
||||||
TypeMenuUtility.GetTypes(baseType),
|
TypeSearch.GetTypes(baseType),
|
||||||
k_MaxTypePopupLineCount,
|
k_MaxTypePopupLineCount,
|
||||||
state
|
state
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,23 +3,11 @@ using System.Linq;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
namespace MackySoft.SerializeReferenceExtensions.Editor {
|
namespace MackySoft.SerializeReferenceExtensions.Editor
|
||||||
|
{
|
||||||
public static class TypeMenuUtility {
|
public static class TypeMenuUtility {
|
||||||
|
|
||||||
public const string k_NullDisplayName = "<null>";
|
public const string k_NullDisplayName = "<null>";
|
||||||
static readonly Type k_UnityObjectType = typeof(UnityEngine.Object);
|
|
||||||
|
|
||||||
public static IEnumerable<Type> GetTypes (Type baseType)
|
|
||||||
{
|
|
||||||
return TypeCache.GetTypesDerivedFrom(baseType).Append(baseType).Where(p =>
|
|
||||||
(p.IsPublic || p.IsNestedPublic || p.IsNestedPrivate) &&
|
|
||||||
!p.IsAbstract &&
|
|
||||||
!p.IsGenericType &&
|
|
||||||
!k_UnityObjectType.IsAssignableFrom(p) &&
|
|
||||||
Attribute.IsDefined(p, typeof(SerializableAttribute)) &&
|
|
||||||
!Attribute.IsDefined(p, typeof(HideInTypeMenuAttribute))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AddTypeMenuAttribute GetAttribute (Type type) {
|
public static AddTypeMenuAttribute GetAttribute (Type type) {
|
||||||
return Attribute.GetCustomAttribute(type,typeof(AddTypeMenuAttribute)) as AddTypeMenuAttribute;
|
return Attribute.GetCustomAttribute(type,typeof(AddTypeMenuAttribute)) as AddTypeMenuAttribute;
|
||||||
|
|||||||
@ -0,0 +1,142 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace MackySoft.SerializeReferenceExtensions.Editor
|
||||||
|
{
|
||||||
|
public static class TypeSearch
|
||||||
|
{
|
||||||
|
|
||||||
|
#if UNITY_2023_2_OR_NEWER
|
||||||
|
static readonly Dictionary<Type, List<Type>> m_TypeCache = new Dictionary<Type, List<Type>>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetTypes (Type baseType)
|
||||||
|
{
|
||||||
|
#if UNITY_2023_2_OR_NEWER
|
||||||
|
// NOTE: This is a workaround for Unity 2023.2 and later.
|
||||||
|
// 2023.2 because SerializeReference supports generic type instances and because the behaviour is stable.
|
||||||
|
if (baseType.IsGenericType)
|
||||||
|
{
|
||||||
|
return GetTypesWithGeneric(baseType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetTypesUsingTypeCache(baseType);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return GetTypesWithGeneric(baseType);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static IEnumerable<Type> GetTypesUsingTypeCache (Type baseType)
|
||||||
|
{
|
||||||
|
return TypeCache.GetTypesDerivedFrom(baseType)
|
||||||
|
.Append(baseType)
|
||||||
|
.Where(IsValidType);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2023_2_OR_NEWER
|
||||||
|
static IEnumerable<Type> GetTypesWithGeneric (Type baseType)
|
||||||
|
{
|
||||||
|
if (m_TypeCache.TryGetValue(baseType, out List<Type> result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = new List<Type>();
|
||||||
|
Type genericTypeDefinition = null;
|
||||||
|
Type[] targetTypeArguments = null;
|
||||||
|
Type[] genericTypeParameters = null;
|
||||||
|
|
||||||
|
if (baseType.IsGenericType)
|
||||||
|
{
|
||||||
|
genericTypeDefinition = baseType.GetGenericTypeDefinition();
|
||||||
|
targetTypeArguments = baseType.GetGenericArguments();
|
||||||
|
genericTypeParameters = genericTypeDefinition.GetGenericArguments();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genericTypeDefinition = baseType;
|
||||||
|
targetTypeArguments = Type.EmptyTypes;
|
||||||
|
genericTypeParameters = Type.EmptyTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<Type> types = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
|
.SelectMany(x => x.GetTypes())
|
||||||
|
.Where(IsValidType);
|
||||||
|
|
||||||
|
foreach (Type type in types)
|
||||||
|
{
|
||||||
|
Type[] interfaceTypes = type.GetInterfaces();
|
||||||
|
foreach (Type interfaceType in interfaceTypes)
|
||||||
|
{
|
||||||
|
if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != genericTypeDefinition)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] sourceTypeArguments = interfaceType.GetGenericArguments();
|
||||||
|
|
||||||
|
bool allParametersMatch = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < genericTypeParameters.Length; i++)
|
||||||
|
{
|
||||||
|
var variance = genericTypeParameters[i].GenericParameterAttributes & GenericParameterAttributes.VarianceMask;
|
||||||
|
|
||||||
|
Type sourceTypeArgument = sourceTypeArguments[i];
|
||||||
|
Type targetTypeArgument = targetTypeArguments[i];
|
||||||
|
|
||||||
|
if (variance == GenericParameterAttributes.Contravariant)
|
||||||
|
{
|
||||||
|
if (!sourceTypeArgument.IsAssignableFrom(targetTypeArgument))
|
||||||
|
{
|
||||||
|
allParametersMatch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (variance == GenericParameterAttributes.Covariant)
|
||||||
|
{
|
||||||
|
if (!targetTypeArgument.IsAssignableFrom(sourceTypeArgument))
|
||||||
|
{
|
||||||
|
allParametersMatch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sourceTypeArgument != targetTypeArgument)
|
||||||
|
{
|
||||||
|
allParametersMatch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allParametersMatch)
|
||||||
|
{
|
||||||
|
result.Add(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_TypeCache.Add(baseType, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool IsValidType (Type type)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(type.IsPublic || type.IsNestedPublic || type.IsNestedPrivate) &&
|
||||||
|
!type.IsAbstract &&
|
||||||
|
!type.IsGenericType &&
|
||||||
|
!typeof(UnityEngine.Object).IsAssignableFrom(type) &&
|
||||||
|
Attribute.IsDefined(type, typeof(SerializableAttribute)) &&
|
||||||
|
!Attribute.IsDefined(type, typeof(HideInTypeMenuAttribute));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5ea24172520aa2646954c1d246e7ba5d
|
||||||
Loading…
x
Reference in New Issue
Block a user