From a786d3992926b39f5b034d90a9ae5cdf6c47860a Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 02:12:04 +0900 Subject: [PATCH 01/15] Add type policy and candidate provider interfaces Introduces IIntrinsicTypePolicy, ITypeCandiateProvider, and ITypeCompatibilityPolicy interfaces with default implementations for type filtering and compatibility checks. Adds Unity 2023.2+ specific implementations to support generic variance in type compatibility and candidate discovery. These abstractions improve extensibility and support for advanced type scenarios in SerializeReferenceExtensions. --- .../Editor/IIntrinsicTypePolicy.cs | 26 ++++ .../Editor/IIntrinsicTypePolicy.cs.meta | 2 + .../Editor/ITypeCandiateProvider.cs | 32 +++++ .../Editor/ITypeCandiateProvider.cs.meta | 2 + .../Editor/ITypeCompatibilityPolicy.cs | 34 +++++ .../Editor/ITypeCompatibilityPolicy.cs.meta | 2 + ..._GenericVarianceTypeCompatibilityPolicy.cs | 128 ++++++++++++++++++ ...ricVarianceTypeCompatibilityPolicy.cs.meta | 2 + ...ity_2023_2_OrNewer_TypeCandiateProvider.cs | 104 ++++++++++++++ ...023_2_OrNewer_TypeCandiateProvider.cs.meta | 2 + 10 files changed, 334 insertions(+) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs new file mode 100644 index 0000000..9f55181 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs @@ -0,0 +1,26 @@ +using System; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public interface IIntrinsicTypePolicy + { + bool IsAllowed (Type candiateType); + } + + public sealed class DefaultIntrinsicTypePolicy : IIntrinsicTypePolicy + { + + public static readonly DefaultIntrinsicTypePolicy Instance = new DefaultIntrinsicTypePolicy(); + + public bool IsAllowed (Type candiateType) + { + return + (candiateType.IsPublic || candiateType.IsNestedPublic || candiateType.IsNestedPrivate) && + !candiateType.IsAbstract && + !candiateType.IsGenericType && + !typeof(UnityEngine.Object).IsAssignableFrom(candiateType) && + Attribute.IsDefined(candiateType, typeof(SerializableAttribute)) && + !Attribute.IsDefined(candiateType, typeof(HideInTypeMenuAttribute)); + } + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs.meta new file mode 100644 index 0000000..2841a2e --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 67c3f8c80bdf1514184495b1ff985d7c \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs new file mode 100644 index 0000000..049c3b7 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public interface ITypeCandiateProvider + { + IEnumerable GetTypeCandidates (Type baseType); + } + + public sealed class DefaultTypeCandiateProvider : ITypeCandiateProvider + { + + public static readonly DefaultTypeCandiateProvider Instance = new DefaultTypeCandiateProvider(DefaultIntrinsicTypePolicy.Instance); + + private readonly IIntrinsicTypePolicy intrinsicTypePolicy; + + public DefaultTypeCandiateProvider (IIntrinsicTypePolicy intrinsicTypePolicy) + { + this.intrinsicTypePolicy = intrinsicTypePolicy ?? throw new ArgumentNullException(nameof(intrinsicTypePolicy)); + } + + public IEnumerable GetTypeCandidates (Type baseType) + { + return TypeCache.GetTypesDerivedFrom(baseType) + .Append(baseType) + .Where(intrinsicTypePolicy.IsAllowed); + } + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs.meta new file mode 100644 index 0000000..4ec4253 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0f3d3f0c0347423459e5e3ef96cf0026 \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs new file mode 100644 index 0000000..5777621 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs @@ -0,0 +1,34 @@ +using System; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public interface ITypeCompatibilityPolicy + { + bool IsCompatible (Type baseType, Type candiateType); + } + + public sealed class DefaultTypeCompatibilityPolicy : ITypeCompatibilityPolicy + { + + public static readonly DefaultTypeCompatibilityPolicy Instance = new DefaultTypeCompatibilityPolicy(); + + public bool IsCompatible (Type baseType, Type candiateType) + { + if (baseType == null) + { + throw new ArgumentNullException(nameof(baseType)); + } + if (candiateType == null) + { + throw new ArgumentNullException(nameof(candiateType)); + } + + if (baseType.IsGenericTypeDefinition || baseType.ContainsGenericParameters) + { + return false; + } + + return baseType.IsAssignableFrom(candiateType); + } + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs.meta new file mode 100644 index 0000000..685ac90 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 657baec9653b0914398f2075153d3275 \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs new file mode 100644 index 0000000..334a8f8 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs @@ -0,0 +1,128 @@ +using System; +using System.Reflection; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ +#if UNITY_2023_2_OR_NEWER + public sealed class Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy : ITypeCompatibilityPolicy + { + + public static readonly Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy Instance = new Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy(); + + public bool IsCompatible (Type baseType, Type candiateType) + { + if (baseType == null) + { + throw new ArgumentNullException(nameof(baseType)); + } + if (candiateType == null) + { + throw new ArgumentNullException(nameof(candiateType)); + } + + // If not generic, fall back to standard assignability check + if (!baseType.IsGenericType) + { + return baseType.IsAssignableFrom(candiateType); + } + + if (baseType.IsGenericTypeDefinition || baseType.ContainsGenericParameters) + { + return false; + } + + // NOTE: baseType is constructed generic type + Type genericTypeDefinition = baseType.GetGenericTypeDefinition(); + Type[] targetTypeArguments = baseType.GetGenericArguments(); + Type[] genericTypeParameters = genericTypeDefinition.GetGenericArguments(); + + // Check interfaces + foreach (Type interfaceType in candiateType.GetInterfaces()) + { + if (!interfaceType.IsGenericType) + { + continue; + } + if (interfaceType.GetGenericTypeDefinition() != genericTypeDefinition) + { + continue; + } + + Type[] sourceTypeArguments = interfaceType.GetGenericArguments(); + if (AreAllGenericArgumentsCompatible(genericTypeParameters, targetTypeArguments, sourceTypeArguments)) + { + return true; + } + } + + // Check base types + for (Type t = candiateType; t != null && t != typeof(object); t = t.BaseType) + { + if (!t.IsGenericType) + { + continue; + } + if (t.GetGenericTypeDefinition() != genericTypeDefinition) + { + continue; + } + + Type[] sourceTypeArguments = t.GetGenericArguments(); + if (AreAllGenericArgumentsCompatible(genericTypeParameters, targetTypeArguments, sourceTypeArguments)) + { + return true; + } + } + + return false; + } + + private static bool AreAllGenericArgumentsCompatible (Type[] genericTypeParameters, Type[] targetTypeArguments, Type[] sourceTypeArguments) + { + if (genericTypeParameters.Length != targetTypeArguments.Length) + { + return false; + } + if (sourceTypeArguments.Length != targetTypeArguments.Length) + { + return false; + } + + 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) + { + // NOTE: in T = source must be able to accept the target. + if (!sourceTypeArgument.IsAssignableFrom(targetTypeArgument)) + { + return false; + } + } + else if (variance == GenericParameterAttributes.Covariant) + { + // NOTE: out T = target must be able to accept the source. + if (!targetTypeArgument.IsAssignableFrom(sourceTypeArgument)) + { + return false; + } + } + else + { + // invariant + if (sourceTypeArgument != targetTypeArgument) + { + return false; + } + } + } + + return true; + } + } +#endif +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta new file mode 100644 index 0000000..919a676 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 342868b30f7a5b442bd48e0ba125f8dc \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs new file mode 100644 index 0000000..07831e6 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs @@ -0,0 +1,104 @@ +#if UNITY_2023_2_OR_NEWER +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public sealed class Unity_2023_2_OrNewer_TypeCandiateProvider : ITypeCandiateProvider + { + + public static readonly Unity_2023_2_OrNewer_TypeCandiateProvider Instance = new Unity_2023_2_OrNewer_TypeCandiateProvider( + DefaultIntrinsicTypePolicy.Instance, + Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.Instance + ); + + private Dictionary> m_TypeCache = new Dictionary>(); + + private readonly IIntrinsicTypePolicy m_IntrinsicTypePolicy; + private readonly ITypeCompatibilityPolicy m_TypeCompatibilityPolicy; + + private Unity_2023_2_OrNewer_TypeCandiateProvider ( + IIntrinsicTypePolicy intrinsicTypePolicy, + ITypeCompatibilityPolicy typeCompatibilityPolicy + ) + { + m_IntrinsicTypePolicy = intrinsicTypePolicy ?? throw new ArgumentNullException(nameof(intrinsicTypePolicy)); + m_TypeCompatibilityPolicy = typeCompatibilityPolicy ?? throw new ArgumentNullException(nameof(typeCompatibilityPolicy)); + } + + public IEnumerable GetTypeCandidates (Type baseType) + { + if (!baseType.IsGenericType) + { + return DefaultTypeCandiateProvider.Instance.GetTypeCandidates(baseType); + } + + return GetTypesWithGeneric(baseType); + } + + private IEnumerable GetTypesWithGeneric (Type baseType) + { + if (m_TypeCache.TryGetValue(baseType, out List result)) + { + return result; + } + + result = new List(); + + IEnumerable types = EnumerateAllTypesSafely(); + foreach (Type type in types) + { + if (!m_IntrinsicTypePolicy.IsAllowed(type)) + { + continue; + } + if (!m_TypeCompatibilityPolicy.IsCompatible(baseType, type)) + { + continue; + } + + result.Add(type); + } + + // Include the base type itself if allowed + if (m_IntrinsicTypePolicy.IsAllowed(baseType) && m_TypeCompatibilityPolicy.IsCompatible(baseType, baseType)) + { + result.Add(baseType); + } + + m_TypeCache.Add(baseType, result); + return result; + } + + private static IEnumerable EnumerateAllTypesSafely () + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + Type[] types; + try + { + types = asm.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + types = ex.Types; + } + + if (types == null) + { + continue; + } + + foreach (var t in types) + { + if (t != null) + { + yield return t; + } + } + } + } + } +} +#endif diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta new file mode 100644 index 0000000..64a280c --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9553ecdd6faccf14db431d2eca328aa9 \ No newline at end of file From 92d1d071224c4873e4ece685f0a4e86d781efdc9 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 02:38:34 +0900 Subject: [PATCH 02/15] Refactor type search logic into TypeCandiateService Replaces TypeSearch with TypeCandiateService and TypeSearchService for improved modularity and extensibility. Updates SubclassSelectorDrawer to use the new service. Removes obsolete TypeSearch and related files. --- .../Editor/SubclassSelectorDrawer.cs | 5 +- .../Editor/TypeCandiateService.cs | 45 ++++++ .../Editor/TypeCandiateService.cs.meta | 2 + .../Editor/TypeSearch.cs | 142 ------------------ .../Editor/TypeSearch.cs.meta | 11 -- .../Editor/TypeSearchService.cs | 26 ++++ .../Editor/TypeSearchService.cs.meta | 2 + 7 files changed, 78 insertions(+), 155 deletions(-) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs.meta delete mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs delete mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs index f87f59c..157725c 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs @@ -150,8 +150,9 @@ TypePopupCache GetTypePopup (SerializedProperty property) { var state = new AdvancedDropdownState(); Type baseType = ManagedReferenceUtility.GetType(managedReferenceFieldTypename); - var popup = new AdvancedTypePopup( - TypeSearch.GetTypes(baseType), + var types = TypeSearchService.TypeCandiateService.GetDisplayableTypes(baseType); + var popup = new AdvancedTypePopup( + types, k_MaxTypePopupLineCount, state ); diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs new file mode 100644 index 0000000..31c63d6 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public sealed class TypeCandiateService + { + + private readonly ITypeCandiateProvider typeCandiateProvider; + private readonly IIntrinsicTypePolicy intrinsicTypePolicy; + private readonly ITypeCompatibilityPolicy typeCompatibilityPolicy; + + private readonly Dictionary typeCache = new Dictionary(); + + public TypeCandiateService (ITypeCandiateProvider typeCandiateProvider, IIntrinsicTypePolicy intrinsicTypePolicy, ITypeCompatibilityPolicy typeCompatibilityPolicy) + { + this.typeCandiateProvider = typeCandiateProvider ?? throw new ArgumentNullException(nameof(typeCandiateProvider)); + this.intrinsicTypePolicy = intrinsicTypePolicy ?? throw new ArgumentNullException(nameof(intrinsicTypePolicy)); + this.typeCompatibilityPolicy = typeCompatibilityPolicy ?? throw new ArgumentNullException(nameof(typeCompatibilityPolicy)); + } + + public IReadOnlyList GetDisplayableTypes (Type baseType) + { + if (baseType == null) + { + throw new ArgumentNullException(nameof(baseType)); + } + if (typeCache.TryGetValue(baseType, out Type[] cachedTypes)) + { + return cachedTypes; + } + + var candiateTypes = typeCandiateProvider.GetTypeCandidates(baseType); + var result = candiateTypes + .Where(intrinsicTypePolicy.IsAllowed) + .Where(t => typeCompatibilityPolicy.IsCompatible(baseType, t)) + .Distinct() + .ToArray(); + + typeCache.Add(baseType, result); + return result; + } + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs.meta new file mode 100644 index 0000000..e0aca9d --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ac8a4cf19e3d741459fb7ce66abe1be4 \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs deleted file mode 100644 index 7b6bd97..0000000 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs +++ /dev/null @@ -1,142 +0,0 @@ -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> m_TypeCache = new Dictionary>(); -#endif - - public static IEnumerable GetTypes (Type baseType) - { -#if UNITY_2023_2_OR_NEWER - // NOTE: This is a generics solution 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 GetTypesUsingTypeCache(baseType); -#endif - } - - static IEnumerable GetTypesUsingTypeCache (Type baseType) - { - return TypeCache.GetTypesDerivedFrom(baseType) - .Append(baseType) - .Where(IsValidType); - } - -#if UNITY_2023_2_OR_NEWER - static IEnumerable GetTypesWithGeneric (Type baseType) - { - if (m_TypeCache.TryGetValue(baseType, out List result)) - { - return result; - } - - result = new List(); - 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 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)); - } - } -} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta deleted file mode 100644 index a9af592..0000000 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5ea24172520aa2646954c1d246e7ba5d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs new file mode 100644 index 0000000..2e85c40 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs @@ -0,0 +1,26 @@ +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public static class TypeSearchService + { + + public static readonly IIntrinsicTypePolicy IntrinsicTypePolicy; + public static readonly ITypeCompatibilityPolicy TypeCompatibilityPolicy; + public static readonly ITypeCandiateProvider TypeCandiateProvider; + public static readonly TypeCandiateService TypeCandiateService; + + static TypeSearchService () + { + IntrinsicTypePolicy = DefaultIntrinsicTypePolicy.Instance; + +#if UNITY_2023_2_OR_NEWER + TypeCompatibilityPolicy = Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.Instance; + TypeCandiateProvider = Unity_2023_2_OrNewer_TypeCandiateProvider.Instance; +#else + TypeCompatibilityPolicy = DefaultTypeCompatibilityPolicy.Instance; + TypeCandiateProvider = DefaultTypeCandiateProvider.Instance; +#endif + + TypeCandiateService = new TypeCandiateService(TypeCandiateProvider, IntrinsicTypePolicy, TypeCompatibilityPolicy); + } + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs.meta new file mode 100644 index 0000000..5645155 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 119c8d609af9df044b30b7deb7cbe359 \ No newline at end of file From bd209f6b98413422bf572f60868958b592d14d2b Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 02:39:55 +0900 Subject: [PATCH 03/15] Update STATUS.md --- STATUS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STATUS.md b/STATUS.md index 5515079..98d8258 100644 --- a/STATUS.md +++ b/STATUS.md @@ -1,3 +1,4 @@ 2026/01/17 -- 2023.2+でなければ、Exampleを開いたときにSerielizeReferenceの共変性・反変性の警告が出るため注意 \ No newline at end of file +- 2023.2+でなければ、Exampleを開いたときにSerielizeReferenceの共変性・反変性の警告が出るため注意 +- 型検索のリファクタ完了。各型の表示を保証するためのテストを作成する \ No newline at end of file From c29681855e3cdcc56dccd3057030557a4c0ed7c3 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 16:29:18 +0900 Subject: [PATCH 04/15] Fix preprocessor directive placement in policy class Moved the UNITY_2023_2_OR_NEWER preprocessor directive to wrap the entire file instead of just the class, ensuring the file is only included for compatible Unity versions. --- ...23_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs index 334a8f8..11df80c 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs @@ -1,9 +1,9 @@ -using System; +#if UNITY_2023_2_OR_NEWER +using System; using System.Reflection; namespace MackySoft.SerializeReferenceExtensions.Editor { -#if UNITY_2023_2_OR_NEWER public sealed class Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy : ITypeCompatibilityPolicy { @@ -124,5 +124,5 @@ private static bool AreAllGenericArgumentsCompatible (Type[] genericTypeParamete return true; } } -#endif -} \ No newline at end of file +} +#endif \ No newline at end of file From a89a0baa18a70b00a4ca609b4d1e6d969f7a776c Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 16:29:35 +0900 Subject: [PATCH 05/15] Move and update test assembly for Editor tests Moved the test assembly definition to an Editor folder, renamed it to MackySoft.SerializeReferenceExtensions.Tests.Editor, and updated its root namespace. Added a placeholder TypeCandidateTestTypes.cs script for future Editor tests. --- .../Tests/Editor.meta | 8 ++++++++ ...Soft.SerializeReferenceExtensions.Tests.Editor.asmdef} | 4 ++-- ...SerializeReferenceExtensions.Tests.Editor.asmdef.meta} | 0 .../Tests/Editor/TypeCandidateTestTypes.cs | 8 ++++++++ .../Tests/Editor/TypeCandidateTestTypes.cs.meta | 2 ++ 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor.meta rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/{MackySoft.SerializeReferenceExtensions.Tests.asmdef => Editor/MackySoft.SerializeReferenceExtensions.Tests.Editor.asmdef} (80%) rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/{MackySoft.SerializeReferenceExtensions.Tests.asmdef.meta => Editor/MackySoft.SerializeReferenceExtensions.Tests.Editor.asmdef.meta} (100%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor.meta new file mode 100644 index 0000000..fa3e6a3 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a458ed0ab99313148aaf87cc2436cdb4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/MackySoft.SerializeReferenceExtensions.Tests.asmdef b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/MackySoft.SerializeReferenceExtensions.Tests.Editor.asmdef similarity index 80% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/MackySoft.SerializeReferenceExtensions.Tests.asmdef rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/MackySoft.SerializeReferenceExtensions.Tests.Editor.asmdef index 5367dc9..8205358 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/MackySoft.SerializeReferenceExtensions.Tests.asmdef +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/MackySoft.SerializeReferenceExtensions.Tests.Editor.asmdef @@ -1,6 +1,6 @@ { - "name": "Tests", - "rootNamespace": "", + "name": "MackySoft.SerializeReferenceExtensions.Tests.Editor", + "rootNamespace": "MackySoft.SerializeReferenceExtensions.Tests", "references": [ "UnityEngine.TestRunner", "UnityEditor.TestRunner", diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/MackySoft.SerializeReferenceExtensions.Tests.asmdef.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/MackySoft.SerializeReferenceExtensions.Tests.Editor.asmdef.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/MackySoft.SerializeReferenceExtensions.Tests.asmdef.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/MackySoft.SerializeReferenceExtensions.Tests.Editor.asmdef.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs new file mode 100644 index 0000000..19c9380 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs @@ -0,0 +1,8 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace MackySoft.SerializeReferenceExtensions.Tests +{ + +} diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs.meta new file mode 100644 index 0000000..a73406d --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: baba1bd524348144ab4131ff5ca8ed89 \ No newline at end of file From 578cdfe58c35ab03308934af19130c4a417481b2 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 17:15:31 +0900 Subject: [PATCH 06/15] Exclude primitive and enum types from intrinsic policy Added checks to filter out primitive and enum types in the intrinsic type policy, ensuring only appropriate types are considered for serialization. --- .../Editor/IIntrinsicTypePolicy.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs index 9f55181..15f7fa1 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs @@ -18,6 +18,8 @@ public bool IsAllowed (Type candiateType) (candiateType.IsPublic || candiateType.IsNestedPublic || candiateType.IsNestedPrivate) && !candiateType.IsAbstract && !candiateType.IsGenericType && + !candiateType.IsPrimitive && + !candiateType.IsEnum && !typeof(UnityEngine.Object).IsAssignableFrom(candiateType) && Attribute.IsDefined(candiateType, typeof(SerializableAttribute)) && !Attribute.IsDefined(candiateType, typeof(HideInTypeMenuAttribute)); From c670d9f178d99e76e01f9bc113eafc8b03f995c3 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 17:18:44 +0900 Subject: [PATCH 07/15] Add comprehensive type candidate service tests Introduces new unit tests for DefaultIntrinsicTypePolicy and TypeCandidateService, covering intrinsic type policy, base type inclusion, generic variance (Unity 2023.2+), and non-generic candidate filtering. Also expands TypeCandidateTestTypes with various test types to support these scenarios. --- .../Editor/DefaultIntrinsicTypePolicyTests.cs | 33 +++++++ .../DefaultIntrinsicTypePolicyTests.cs.meta | 2 + .../TypeCandidateService_BaseTypeSelfTests.cs | 20 +++++ ...CandidateService_BaseTypeSelfTests.cs.meta | 2 + ...peCandidateService_GenericVarianceTests.cs | 44 ++++++++++ ...didateService_GenericVarianceTests.cs.meta | 2 + .../TypeCandidateService_NonGenericTests.cs | 56 ++++++++++++ ...peCandidateService_NonGenericTests.cs.meta | 2 + .../Tests/Editor/TypeCandidateTestTypes.cs | 88 ++++++++++++++++++- 9 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs new file mode 100644 index 0000000..6377b97 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using MackySoft.SerializeReferenceExtensions.Editor; +using NUnit.Framework; + +namespace MackySoft.SerializeReferenceExtensions.Tests +{ + public sealed class DefaultIntrinsicTypePolicyTests + { + public static IEnumerable Cases () + { + yield return new TestCaseData(typeof(PublicSerializableClass), true).SetName("Intrinsic_PublicSerializableClass_OK"); + yield return new TestCaseData(typeof(SerializableStruct), true).SetName("Intrinsic_ValueTypeStruct_OK"); + yield return new TestCaseData(typeof(Outer.NestedPublicSerializableClass), true).SetName("Intrinsic_NestedPublic_OK"); + yield return new TestCaseData(Outer.NestedPrivateType, true).SetName("Intrinsic_NestedPrivate_OK"); + + yield return new TestCaseData(typeof(InternalSerializableClass), false).SetName("Intrinsic_Internal_NG"); + yield return new TestCaseData(typeof(AbstractSerializableClass), false).SetName("Intrinsic_Abstract_NG"); + yield return new TestCaseData(typeof(NonSerializableClass), false).SetName("Intrinsic_NoSerializableAttribute_NG"); + yield return new TestCaseData(typeof(HiddenSerializableClass), false).SetName("Intrinsic_HideInTypeMenu_NG"); + yield return new TestCaseData(typeof(UnityObjectDerived), false).SetName("Intrinsic_UnityObjectDerived_NG"); + + yield return new TestCaseData(typeof(GenericCandidate), false).SetName("Intrinsic_GenericClosed_NG"); + } + + [TestCaseSource(nameof(Cases))] + public void IsAllowed_MatchesExpected (Type type, bool expected) + { + bool actual = DefaultIntrinsicTypePolicy.Instance.IsAllowed(type); + Assert.That(actual, Is.EqualTo(expected), type.FullName); + } + } +} diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs.meta new file mode 100644 index 0000000..be1e87f --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 497d6617d2c784d418845bc691d6344c \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs new file mode 100644 index 0000000..283bc5c --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs @@ -0,0 +1,20 @@ +using System.Linq; +using MackySoft.SerializeReferenceExtensions.Editor; +using NUnit.Framework; + +namespace MackySoft.SerializeReferenceExtensions.Tests +{ + [TestFixture] + public sealed class TypeCandidateService_BaseTypeSelfTests + { + [Test] + public void ConcreteBaseType_IsIncluded () + { + var set = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(ConcreteBaseType)).ToHashSet(); + + Assert.That(set, Does.Contain(typeof(ConcreteBaseType))); + Assert.That(set, Does.Contain(typeof(ConcreteDerivedType))); + Assert.That(set, !Does.Contain(typeof(ConcreteInternalDerivedType))); + } + } +} diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs.meta new file mode 100644 index 0000000..6b0421f --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_BaseTypeSelfTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3617b1f123decbc4f90ecc60be3bd12f \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs new file mode 100644 index 0000000..b5b71f5 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs @@ -0,0 +1,44 @@ +#if UNITY_2023_2_OR_NEWER +using System.Linq; +using MackySoft.SerializeReferenceExtensions.Editor; +using NUnit.Framework; + +namespace MackySoft.SerializeReferenceExtensions.Tests +{ + [TestFixture] + public sealed class TypeCandidateService_GenericVarianceTests + { + [Test] + public void Contravariance_IsSupported () + { + // baseType: IContravariance + var set = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(IContravariant)).ToHashSet(); + + Assert.That(set, Does.Contain(typeof(Contravariant_NetworkActor)), "Exact match should be included."); + Assert.That(set, Does.Contain(typeof(Contravariant_Actor)), "Contravariant match should be included."); + Assert.That(set, !Does.Contain(typeof(Contravariant_DerivedNetworkActor)), "Narrower type argument should be excluded."); + } + + [Test] + public void Covariance_IsSupported () + { + // baseType: ICovariant + var set = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(ICovariant)).ToHashSet(); + + Assert.That(set, Does.Contain(typeof(Covariant_Actor)), "Exact match should be included."); + Assert.That(set, Does.Contain(typeof(Covariant_NetworkActor)), "Covariant match should be included."); + Assert.That(set, !Does.Contain(typeof(Covariant_Object)), "Wider type argument should be excluded."); + } + + [Test] + public void Invariance_RemainsStrict () + { + // baseType: IInvariant + var set = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(IInvariant)).ToHashSet(); + + Assert.That(set, Does.Contain(typeof(Invariant_Actor))); + Assert.That(set, !Does.Contain(typeof(Invariant_NetworkActor))); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs.meta new file mode 100644 index 0000000..2a652eb --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 43a0ca9780c90f147af2b5901b9b05d1 \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs new file mode 100644 index 0000000..d677fbb --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs @@ -0,0 +1,56 @@ +using System; +using System.CodeDom; +using System.Collections.Generic; +using System.Linq; +using MackySoft.SerializeReferenceExtensions.Editor; +using NUnit.Framework; + +namespace MackySoft.SerializeReferenceExtensions.Tests +{ + [TestFixture] + public sealed class TypeCandidateService_NonGenericTests + { + private HashSet candidates; + + [OneTimeSetUp] + public void OneTimeSetUp () + { + candidates = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(ITestBase)).ToHashSet(); + } + + public static IEnumerable Cases () + { + yield return new TestCaseData(typeof(PublicSerializableClass), true).SetName("Candidates_ITestBase_PublicSerializable_OK"); + yield return new TestCaseData(typeof(SerializableStruct), true).SetName("Candidates_ITestBase_ValueTypeStruct_OK"); + yield return new TestCaseData(typeof(Outer.NestedPublicSerializableClass), true).SetName("Candidates_ITestBase_NestedPublic_OK"); + yield return new TestCaseData(Outer.NestedPrivateType, true).SetName("Candidates_ITestBase_NestedPrivate_OK"); + + yield return new TestCaseData(typeof(InternalSerializableClass), false).SetName("Candidates_ITestBase_Internal_NG"); + yield return new TestCaseData(typeof(AbstractSerializableClass), false).SetName("Candidates_ITestBase_Abstract_NG"); + yield return new TestCaseData(typeof(NonSerializableClass), false).SetName("Candidates_ITestBase_NoSerializable_NG"); + yield return new TestCaseData(typeof(HiddenSerializableClass), false).SetName("Candidates_ITestBase_HideInTypeMenu_NG"); + yield return new TestCaseData(typeof(UnityObjectDerived), false).SetName("Candidates_ITestBase_UnityObjectDerived_NG"); + yield return new TestCaseData(typeof(GenericCandidate), false).SetName("Candidates_ITestBase_GenericClosed_NG"); + } + + [TestCaseSource(nameof(Cases))] + public void CandidatesContainment_IsExpected (Type type, bool expected) + { + if (expected) + { + Assert.That(candidates, Does.Contain(type), $"Expected to contain: {type.FullName}"); + } + else + { + Assert.That(candidates, !Does.Contain(type), $"Expected NOT to contain: {type.FullName}"); + } + } + + [Test] + public void Candidates_HaveNoDuplicates () + { + var list = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(ITestBase)).ToList(); + Assert.That(list.Count, Is.EqualTo(list.Distinct().Count())); + } + } +} diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs.meta new file mode 100644 index 0000000..0512649 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_NonGenericTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ea32323e9ba718a42839ac09aaf4a5b5 \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs index 19c9380..b3e1ce3 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs @@ -1,8 +1,94 @@ +using System; using System.Collections; -using System.Collections.Generic; +using System.Reflection; using UnityEngine; namespace MackySoft.SerializeReferenceExtensions.Tests { + public interface ITestBase { } + + [Serializable] + public sealed class PublicSerializableClass : ITestBase { } + + [Serializable] + internal sealed class InternalSerializableClass : ITestBase { } + + [Serializable] + public abstract class AbstractSerializableClass : ITestBase { } + + public sealed class NonSerializableClass : ITestBase { } + + [Serializable, HideInTypeMenu] + public sealed class HiddenSerializableClass : ITestBase { } + + [Serializable] + public sealed class UnityObjectDerived : ScriptableObject, ITestBase { } + + public sealed class Outer + { + [Serializable] + public sealed class NestedPublicSerializableClass : ITestBase { } + + [Serializable] + private sealed class NestedPrivateSerializableClass : ITestBase { } + + public static Type NestedPrivateType => typeof(Outer).GetNestedType(nameof(NestedPrivateSerializableClass), BindingFlags.NonPublic); + } + + [Serializable] + public sealed class GenericCandidate : ITestBase { } + + [Serializable] + public struct SerializableStruct : ITestBase { } + + [Serializable] + public class ConcreteBaseType { } + + [Serializable] + public sealed class ConcreteDerivedType : ConcreteBaseType { } + + [Serializable] + internal sealed class ConcreteInternalDerivedType : ConcreteBaseType { } + + // ------------------------ + // Generic variance test types (2023.2+) + // ------------------------ + public interface IActor { } + public interface INetworkActor : IActor { } + public interface IDerivedNetworkActor : INetworkActor { } + + public interface IContravariant { } + public interface ICovariant { T Create (); } + public interface IInvariant { } + + [Serializable] + public sealed class Contravariant_Actor : IContravariant { } + + [Serializable] + public sealed class Contravariant_NetworkActor : IContravariant { } + + [Serializable] + public sealed class Contravariant_DerivedNetworkActor : IContravariant { } + + [Serializable] + public sealed class Covariant_Actor : ICovariant { + public IActor Create () => null; + } + + [Serializable] + public sealed class Covariant_NetworkActor : ICovariant { + public INetworkActor Create () => null; + } + + [Serializable] + public sealed class Covariant_Object : ICovariant { + public object Create () => null; + } + + [Serializable] + public sealed class Invariant_Actor : IInvariant { } + + [Serializable] + public sealed class Invariant_NetworkActor : IInvariant { } } From b0ab5a8472938316f3c40afadcdfc9063917d2e7 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 17:43:16 +0900 Subject: [PATCH 08/15] Update Example_Generics.cs --- Assets/Example/Example_Generics.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Assets/Example/Example_Generics.cs b/Assets/Example/Example_Generics.cs index bc4f604..f94145e 100644 --- a/Assets/Example/Example_Generics.cs +++ b/Assets/Example/Example_Generics.cs @@ -85,6 +85,12 @@ public class Example_Generics : MonoBehaviour { [SerializeReference, SubclassSelector] + public IContravarianceAction contravarianceAction = null; + + [SerializeReference, SubclassSelector] + public BaseAction baseAction = null; + + [SerializeReference, SubclassSelector] public List> contravarianceActions = new List>(); [SerializeReference, SubclassSelector] From 21dd46c51f73483b7c4263ebeca58c361308ae18 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 18:32:14 +0900 Subject: [PATCH 09/15] Create tests.yaml --- .github/workflows/tests.yaml | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/tests.yaml diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..1a4225f --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,55 @@ +name: Tests + +on: + push: + branches-ignore: + - documentation + - gh-pages + pull_request: {} + +jobs: + test: + name: ${{ matrix.testMode }} on Unity ${{ matrix.unityVersion }} + + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + projectPath: + - . + unityVersion: + - 2021.3.45f2 + - 2023.2.22f1 + testMode: + - editmode + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + lfs: true + + - name: Cache + uses: actions/cache@v4 + with: + path: ${{ matrix.projectPath }}/Library + key: Library-${{ runner.os }}-${{ matrix.projectPath }}-${{ matrix.unityVersion }}-${{ matrix.testMode }}-${{ hashFiles('**/Packages/manifest.json', '**/Packages/packages-lock.json', '**/ProjectSettings/ProjectVersion.txt') }} + restore-keys: | + Library-${{ runner.os }}-${{ matrix.projectPath }}-${{ matrix.unityVersion }}-${{ matrix.testMode }}- + Library-${{ runner.os }}-${{ matrix.projectPath }}-${{ matrix.unityVersion }}- + Library-${{ runner.os }}-${{ matrix.projectPath }}- + + - name: Tests + uses: game-ci/unity-test-runner@v4 + id: tests + env: + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} + UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} + with: + projectPath: ${{ matrix.projectPath }} + unityVersion: ${{ matrix.unityVersion }} + testMode: ${{ matrix.testMode }} + artifactsPath: test-results + artifactsName: TestResults-${{ matrix.unityVersion }}-${{ matrix.testMode }} From 3493d40f9dac7fd2ecce370e9fa8118823bc6c3d Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 18:46:54 +0900 Subject: [PATCH 10/15] Refactor type search policies and providers structure Moved type search-related interfaces and implementations into a new Editor/TypeSearch folder for better organization. Updated file paths and separated interface definitions from their default implementations. --- .../Editor/TypeSearch.meta | 8 ++++++++ .../Editor/TypeSearch/IIntrinsicTypePolicy.cs | 9 +++++++++ .../{ => TypeSearch}/IIntrinsicTypePolicy.cs.meta | 0 .../Editor/TypeSearch/ITypeCandiateProvider.cs | 10 ++++++++++ .../{ => TypeSearch}/ITypeCandiateProvider.cs.meta | 0 .../Editor/TypeSearch/ITypeCompatibilityPolicy.cs | 9 +++++++++ .../{ => TypeSearch}/ITypeCompatibilityPolicy.cs.meta | 0 .../Editor/TypeSearch/IntrinsicTypePolicy.meta | 8 ++++++++ .../IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs} | 5 ----- .../DefaultIntrinsicTypePolicy.cs.meta | 2 ++ .../Editor/TypeSearch/TypeCandiateProvider.meta | 8 ++++++++ .../DefaultTypeCandiateProvider.cs} | 5 ----- .../DefaultTypeCandiateProvider.cs.meta | 2 ++ .../Unity_2023_2_OrNewer_TypeCandiateProvider.cs | 0 .../Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta | 0 .../Editor/{ => TypeSearch}/TypeCandiateService.cs | 0 .../{ => TypeSearch}/TypeCandiateService.cs.meta | 0 .../Editor/TypeSearch/TypeCompatibilityPolicy.meta | 8 ++++++++ .../DefaultTypeCompatibilityPolicy.cs} | 5 ----- .../DefaultTypeCompatibilityPolicy.cs.meta | 2 ++ ...2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs | 0 ...ewer_GenericVarianceTypeCompatibilityPolicy.cs.meta | 0 .../Editor/{ => TypeSearch}/TypeSearchService.cs | 0 .../Editor/{ => TypeSearch}/TypeSearchService.cs.meta | 0 24 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch}/IIntrinsicTypePolicy.cs.meta (100%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCandiateProvider.cs rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch}/ITypeCandiateProvider.cs.meta (100%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCompatibilityPolicy.cs rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch}/ITypeCompatibilityPolicy.cs.meta (100%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy.meta rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{IIntrinsicTypePolicy.cs => TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs} (89%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs.meta create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider.meta rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ITypeCandiateProvider.cs => TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs} (89%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs.meta rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch/TypeCandiateProvider}/Unity_2023_2_OrNewer_TypeCandiateProvider.cs (100%) rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch/TypeCandiateProvider}/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta (100%) rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch}/TypeCandiateService.cs (100%) rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch}/TypeCandiateService.cs.meta (100%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy.meta rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ITypeCompatibilityPolicy.cs => TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs} (87%) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs.meta rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch/TypeCompatibilityPolicy}/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs (100%) rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch/TypeCompatibilityPolicy}/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta (100%) rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch}/TypeSearchService.cs (100%) rename Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/{ => TypeSearch}/TypeSearchService.cs.meta (100%) diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.meta new file mode 100644 index 0000000..648076c --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 565d90a06c6ff6d45881a68742e61f5b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs new file mode 100644 index 0000000..b707ef4 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs @@ -0,0 +1,9 @@ +using System; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public interface IIntrinsicTypePolicy + { + bool IsAllowed (Type candiateType); + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCandiateProvider.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCandiateProvider.cs new file mode 100644 index 0000000..ea65b44 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCandiateProvider.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public interface ITypeCandiateProvider + { + IEnumerable GetTypeCandidates (Type baseType); + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCandiateProvider.cs.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCandiateProvider.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCompatibilityPolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCompatibilityPolicy.cs new file mode 100644 index 0000000..612d689 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCompatibilityPolicy.cs @@ -0,0 +1,9 @@ +using System; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public interface ITypeCompatibilityPolicy + { + bool IsCompatible (Type baseType, Type candiateType); + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCompatibilityPolicy.cs.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/ITypeCompatibilityPolicy.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy.meta new file mode 100644 index 0000000..d1d6e71 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 954f01eacf065bb409380a285e789133 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs similarity index 89% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs index 15f7fa1..d7158ae 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/IIntrinsicTypePolicy.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs @@ -2,11 +2,6 @@ namespace MackySoft.SerializeReferenceExtensions.Editor { - public interface IIntrinsicTypePolicy - { - bool IsAllowed (Type candiateType); - } - public sealed class DefaultIntrinsicTypePolicy : IIntrinsicTypePolicy { diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs.meta new file mode 100644 index 0000000..b83bcbd --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2e5f93f8c91d2cf4188bb5a20ba23767 \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider.meta new file mode 100644 index 0000000..8304904 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 89e60a25798499c40a631afebaa392e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs similarity index 89% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs index 049c3b7..49b18bd 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCandiateProvider.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs @@ -5,11 +5,6 @@ namespace MackySoft.SerializeReferenceExtensions.Editor { - public interface ITypeCandiateProvider - { - IEnumerable GetTypeCandidates (Type baseType); - } - public sealed class DefaultTypeCandiateProvider : ITypeCandiateProvider { diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs.meta new file mode 100644 index 0000000..2a11b33 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 26d67765ac30b4040b240089ae466c64 \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeCandiateService.cs.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy.meta new file mode 100644 index 0000000..c594fc7 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93cc4fbdac6a5054580dbf1f197092f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs similarity index 87% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs index 5777621..8b80dac 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ITypeCompatibilityPolicy.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs @@ -2,11 +2,6 @@ namespace MackySoft.SerializeReferenceExtensions.Editor { - public interface ITypeCompatibilityPolicy - { - bool IsCompatible (Type baseType, Type candiateType); - } - public sealed class DefaultTypeCompatibilityPolicy : ITypeCompatibilityPolicy { diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs.meta new file mode 100644 index 0000000..b33436b --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/DefaultTypeCompatibilityPolicy.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e2a0be0521ea0864ebad1ee2ba4af27f \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCompatibilityPolicy/Unity_2023_2_OrNewer_GenericVarianceTypeCompatibilityPolicy.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs.meta similarity index 100% rename from Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearchService.cs.meta rename to Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs.meta From 1fac9d2de8d47f81c47880cd94f4318459c95578 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 19:28:24 +0900 Subject: [PATCH 11/15] Create AGENTS.md --- AGENTS.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..37a5059 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,36 @@ +# Unity-SerializeReferenceExtensions — AGENTS.md + +## Project overview +This repository provides editor tooling for Unity's [SerializeReference], including `SubclassSelector` +to pick concrete implementations of interfaces / abstract types in the Inspector. + +Primary risk area: type discovery & filtering (what types appear in the selector). + +## Repository layout +- Repository URL: `https://github.com/mackysoft/Unity-SerializeReferenceExtensions` +- Package source: `Assets/MackySoft/MackySoft.SerializeReferenceExtensions` +- Editor code: `.../Editor/**` +- Tests: `.../Tests/**` + +## Unity compatibility (critical) +- Minimum supported Unity: 2021.3 (baseline for development/testing). +- Unity 2023.2+ has enhanced generic type support (variance, etc.). Changes must not break 2021.3 behavior and guarded by `UNITY_2023_2_OR_NEWER`. + +## CI (GitHub Actions) +I use GameCI `unity-test-runner`. +- Always run EditMode tests. +- Run a Unity matrix that includes: + - 2021.3.x (minimum baseline) + - 2023.2+ (generic/variance feature gate) + +## Architecture guardrails +- Runtime surface area should remain minimal (mainly attributes / data structures). +- Editor implementation (PropertyDrawer/UI/type search) must stay under `Editor/`. +- Avoid introducing UnityEditor references into Runtime assemblies. + +## Coding conventions +- Prefer `UnityEditor.TypeCache` for type discovery. Avoid full AppDomain scans unless necessary. +- Keep allocations low in IMGUI paths (e.g., `OnGUI`). +- Keep public API stable; if changing type filtering behavior, add/adjust tests. +- As a general rule, you should follow the restrictions on SerializeReference in Unity's official documentation. + - https://docs.unity3d.com/ScriptReference/SerializeReference.html \ No newline at end of file From f9ea9a99ec97ca75cbd3aca344bbd5f6d36884e7 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 19:38:38 +0900 Subject: [PATCH 12/15] Update Unity build workflow credentials and version Replaces UNITY_LICENSE_2020 with UNITY_LICENSE, adds UNITY_EMAIL and UNITY_PASSWORD environment variables, and sets unityVersion to 2021.3.45f2 for the build job. --- .github/workflows/build.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 2614402..3f31c6f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -41,6 +41,9 @@ jobs: - name: Build uses: game-ci/unity-builder@v4 env: - UNITY_LICENSE: ${{ secrets.UNITY_LICENSE_2020 }} + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} + UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} with: targetPlatform: ${{ matrix.targetPlatform }} + unityVersion: 2021.3.45f2 From eed710027f8e32dcaef7a0c42cccfc5df46adee2 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 19:41:46 +0900 Subject: [PATCH 13/15] Update Unity version and license secret in workflows Changed Unity version from 2021.3.29f1 to 2021.3.45f2 in both package and release workflows. Updated UNITY_LICENSE secret reference in package workflow to use the generic UNITY_LICENSE variable. --- .github/workflows/package.yaml | 4 ++-- .github/workflows/release.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/package.yaml b/.github/workflows/package.yaml index b22b69c..f83c6c3 100644 --- a/.github/workflows/package.yaml +++ b/.github/workflows/package.yaml @@ -5,7 +5,7 @@ on: push: { branches: [main] } env: - UNITY_LICENSE: ${{ secrets.UNITY_LICENSE_2020 }} + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} jobs: build: @@ -34,7 +34,7 @@ jobs: UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} with: - unityVersion: 2021.3.29f1 + unityVersion: 2021.3.45f2 buildMethod: MackySoft.PackageTools.Editor.UnityPackageExporter.Export # Upload diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4537728..57149e8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -65,9 +65,9 @@ jobs: needs: [update-packagejson] strategy: matrix: - unity: ["2021.3.29f1"] + unity: ["2021.3.45f2"] include: - - unityVersion: 2021.3.29f1 + - unityVersion: 2021.3.45f2 license: UNITY_LICENSE runs-on: ubuntu-latest timeout-minutes: 15 From 6ec00ab1b1eb74935a7b6c01914ef895a7712c83 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 19:48:46 +0900 Subject: [PATCH 14/15] Update AGENTS.md --- AGENTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 37a5059..f88914b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,6 +23,11 @@ I use GameCI `unity-test-runner`. - 2021.3.x (minimum baseline) - 2023.2+ (generic/variance feature gate) +## How to run tests locally +### EditMode +Run Unity in batchmode: +- `Unity -batchmode -nographics -quit -projectPath . -runTests -testPlatform editmode -testResults ./TestResults/editmode.xml` + ## Architecture guardrails - Runtime surface area should remain minimal (mainly attributes / data structures). - Editor implementation (PropertyDrawer/UI/type search) must stay under `Editor/`. From ac2e1b9aabe7c894add09f2c7c9f6f9e7b34194b Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 18 Jan 2026 19:54:36 +0900 Subject: [PATCH 15/15] Update AGENTS.md --- AGENTS.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index f88914b..8a4dc9d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,7 +26,17 @@ I use GameCI `unity-test-runner`. ## How to run tests locally ### EditMode Run Unity in batchmode: -- `Unity -batchmode -nographics -quit -projectPath . -runTests -testPlatform editmode -testResults ./TestResults/editmode.xml` +``` +PROJECT_ROOT="$(pwd)" +RESULT_XML="$PROJECT_ROOT/TestResults/editmode.xml" + +mkdir -p "$(dirname "$RESULT_XML")" + +"" -batchmode -nographics -quit \ + -projectPath "$PROJECT_ROOT" \ + -runTests -testPlatform editmode \ + -testResults "$RESULT_XML" +``` ## Architecture guardrails - Runtime surface area should remain minimal (mainly attributes / data structures).