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);
|
||||
var popup = new AdvancedTypePopup(
|
||||
TypeMenuUtility.GetTypes(baseType),
|
||||
TypeSearch.GetTypes(baseType),
|
||||
k_MaxTypePopupLineCount,
|
||||
state
|
||||
);
|
||||
|
||||
@ -3,23 +3,11 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MackySoft.SerializeReferenceExtensions.Editor {
|
||||
namespace MackySoft.SerializeReferenceExtensions.Editor
|
||||
{
|
||||
public static class TypeMenuUtility {
|
||||
|
||||
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) {
|
||||
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