diff --git a/Assets/Example/Example_Generics.cs b/Assets/Example/Example_Generics.cs index 450eb66..da98d1c 100644 --- a/Assets/Example/Example_Generics.cs +++ b/Assets/Example/Example_Generics.cs @@ -83,6 +83,32 @@ public void DoAction (IActor actor) public IActor Actor => null; } +namespace TestExample.Generics +{ + public interface IObjectHolder + { + T Value { get; } + } + + [Serializable] + public sealed class ObjectHolder : IObjectHolder + { + [SerializeField] + private T value; + + public T Value => value; + } + + [Serializable] + public sealed class ParticleSystemHolder : IObjectHolder + { + [SerializeField] + private ParticleSystem value; + + public ParticleSystem Value => value; + } +} + public class Example_Generics : MonoBehaviour { @@ -98,4 +124,10 @@ public class Example_Generics : MonoBehaviour [SerializeReference, SubclassSelector] public List> covarianceActions = new List>(); + [SerializeReference, SubclassSelector] + public TestExample.Generics.IObjectHolder gameObjectHolder = null; + + [SerializeReference, SubclassSelector] + public TestExample.Generics.IObjectHolder particleSystemHolder = null; + } diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs index 497ca62..d873c48 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs @@ -24,10 +24,14 @@ public static string[] GetSplittedTypePath (Type type) } else { - int splitIndex = type.FullName.LastIndexOf('.'); + // In the case of Generic, type information is included as shown below, so it must be extracted. + // TestNamespace.TestClass`1[[UnityEngine.GameObject, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] + var name = type.IsGenericType ? type.FullName.Substring(0, type.FullName.IndexOf("[")) : type.FullName; + + int splitIndex = name.LastIndexOf('.'); if (splitIndex >= 0) { - return new string[] { type.FullName.Substring(0, splitIndex), type.FullName.Substring(splitIndex + 1) }; + return new string[] { name.Substring(0, splitIndex), name.Substring(splitIndex + 1) }; } else { diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs index b707ef4..59b8c26 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IIntrinsicTypePolicy.cs @@ -4,6 +4,6 @@ namespace MackySoft.SerializeReferenceExtensions.Editor { public interface IIntrinsicTypePolicy { - bool IsAllowed (Type candiateType); + bool IsAllowed (Type candiateType, bool ignoreGenericTypeCheck); } } \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs index d7158ae..6e68949 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/IntrinsicTypePolicy/DefaultIntrinsicTypePolicy.cs @@ -1,4 +1,5 @@ using System; +using UnityEngine; namespace MackySoft.SerializeReferenceExtensions.Editor { @@ -7,12 +8,12 @@ public sealed class DefaultIntrinsicTypePolicy : IIntrinsicTypePolicy public static readonly DefaultIntrinsicTypePolicy Instance = new DefaultIntrinsicTypePolicy(); - public bool IsAllowed (Type candiateType) + public bool IsAllowed (Type candiateType, bool ignoreGenericTypeCheck) { return (candiateType.IsPublic || candiateType.IsNestedPublic || candiateType.IsNestedPrivate) && !candiateType.IsAbstract && - !candiateType.IsGenericType && + (ignoreGenericTypeCheck || !candiateType.IsGenericType) && !candiateType.IsPrimitive && !candiateType.IsEnum && !typeof(UnityEngine.Object).IsAssignableFrom(candiateType) && diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs index 49b18bd..4a5ad7f 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/DefaultTypeCandiateProvider.cs @@ -21,7 +21,7 @@ public IEnumerable GetTypeCandidates (Type baseType) { return TypeCache.GetTypesDerivedFrom(baseType) .Append(baseType) - .Where(intrinsicTypePolicy.IsAllowed); + .Where(x => intrinsicTypePolicy.IsAllowed(x, false)); } } } \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs index 4ed3c3c..b43500a 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateProvider/Unity_2023_2_OrNewer_TypeCandiateProvider.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using UnityEditor; namespace MackySoft.SerializeReferenceExtensions.Editor { @@ -46,23 +47,29 @@ private IEnumerable GetTypesWithGeneric (Type baseType) result = new List(); - IEnumerable types = EnumerateAllTypesSafely(); + bool isGenericBaseType = baseType.IsGenericType; + Type genericTypeDefinition = isGenericBaseType ? baseType.GetGenericTypeDefinition() : baseType; + Type[] targetTypeArguments = isGenericBaseType ? baseType.GetGenericArguments() : Type.EmptyTypes; + IEnumerable types = TypeCache.GetTypesDerivedFrom(genericTypeDefinition); foreach (Type type in types) { - if (!intrinsicTypePolicy.IsAllowed(type)) + // If the type is Generic, create a MakeGenericType from the Arguments of the baseType. + Type targetType = type.IsGenericType ? type.MakeGenericType(targetTypeArguments) : type; + + if (!intrinsicTypePolicy.IsAllowed(targetType, targetType != type)) { continue; } - if (!typeCompatibilityPolicy.IsCompatible(baseType, type)) + if (!typeCompatibilityPolicy.IsCompatible(baseType, targetType)) { continue; } - result.Add(type); + result.Add(targetType); } // Include the base type itself if allowed - if (intrinsicTypePolicy.IsAllowed(baseType) && typeCompatibilityPolicy.IsCompatible(baseType, baseType)) + if (intrinsicTypePolicy.IsAllowed(baseType, false) && typeCompatibilityPolicy.IsCompatible(baseType, baseType)) { result.Add(baseType); } diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs index 31c63d6..2bfb139 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs @@ -8,16 +8,12 @@ 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) + public TypeCandiateService (ITypeCandiateProvider typeCandiateProvider) { 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) @@ -33,8 +29,6 @@ public IReadOnlyList GetDisplayableTypes (Type baseType) var candiateTypes = typeCandiateProvider.GetTypeCandidates(baseType); var result = candiateTypes - .Where(intrinsicTypePolicy.IsAllowed) - .Where(t => typeCompatibilityPolicy.IsCompatible(baseType, t)) .Distinct() .ToArray(); diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs index 2e85c40..4880e2c 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeSearchService.cs @@ -3,24 +3,18 @@ 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); + TypeCandiateService = new TypeCandiateService(TypeCandiateProvider); } } } \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs index 6377b97..ecca167 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/DefaultIntrinsicTypePolicyTests.cs @@ -26,7 +26,7 @@ public static IEnumerable Cases () [TestCaseSource(nameof(Cases))] public void IsAllowed_MatchesExpected (Type type, bool expected) { - bool actual = DefaultIntrinsicTypePolicy.Instance.IsAllowed(type); + bool actual = DefaultIntrinsicTypePolicy.Instance.IsAllowed(type, false); Assert.That(actual, Is.EqualTo(expected), type.FullName); } } diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs index b5b71f5..08e2678 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateService_GenericVarianceTests.cs @@ -2,6 +2,7 @@ using System.Linq; using MackySoft.SerializeReferenceExtensions.Editor; using NUnit.Framework; +using UnityEngine; namespace MackySoft.SerializeReferenceExtensions.Tests { @@ -39,6 +40,33 @@ public void Invariance_RemainsStrict () Assert.That(set, Does.Contain(typeof(Invariant_Actor))); Assert.That(set, !Does.Contain(typeof(Invariant_NetworkActor))); } + + [Test] + public void GenericClass_ParticleSystem_IsSupported () + { + var set = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(IObjectHolder)).ToHashSet(); + + Assert.That(set, Does.Contain(typeof(ObjectHolder))); + Assert.That(set, Does.Contain(typeof(ParticleSystemHolder))); + } + + [Test] + public void GenericClass_GameObject_IsSupported () + { + var set = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(IObjectHolder)).ToHashSet(); + + Assert.That(set, Does.Contain(typeof(ObjectHolder))); + Assert.That(set, !Does.Contain(typeof(ParticleSystemHolder))); + } + + [Test] + public void GenericClass_Integer_IsSupported () + { + var set = TypeSearchService.TypeCandiateService.GetDisplayableTypes(typeof(IObjectHolder)).ToHashSet(); + + Assert.That(set, Does.Contain(typeof(ObjectHolder))); + Assert.That(set, !Does.Contain(typeof(ParticleSystemHolder))); + } } } #endif \ 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 f73c113..4be39ce 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Tests/Editor/TypeCandidateTestTypes.cs @@ -61,6 +61,8 @@ public interface IContravariant { } public interface ICovariant { T Create (); } public interface IInvariant { } + public interface IObjectHolder { } + [Serializable] public sealed class Contravariant_Actor : IContravariant { } @@ -93,4 +95,10 @@ public sealed class Invariant_Actor : IInvariant { } [Serializable] public sealed class Invariant_NetworkActor : IInvariant { } + + [Serializable] + public sealed class ObjectHolder : IObjectHolder { } + + [Serializable] + public sealed class ParticleSystemHolder : IObjectHolder { } }