From 0e00a08ca1949c799ba14ab0369fb64451d601f3 Mon Sep 17 00:00:00 2001 From: Marcel Vielhaus Date: Tue, 10 Dec 2024 17:37:49 +0100 Subject: [PATCH] Filter generic base types when seaching for the resource proxy type When inheriting from a generic base type without adding additional interfaces, a resource can still have a generated proxy. However, in that case the proxy builder would assume the generic base type to be the best possible fit, which cannot be proxified. --- .../Resources/ResourceTypeController.cs | 8 +++++--- .../Mocks/ResourceWithGenericMethod.cs | 6 ++++++ .../TypeControllerTests.cs | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Moryx.Resources.Management/Resources/ResourceTypeController.cs b/src/Moryx.Resources.Management/Resources/ResourceTypeController.cs index 893ef29a1..5140fb217 100644 --- a/src/Moryx.Resources.Management/Resources/ResourceTypeController.cs +++ b/src/Moryx.Resources.Management/Resources/ResourceTypeController.cs @@ -264,17 +264,19 @@ private ResourceProxy InstantiateProxy(string typeName, Resource instance) /// private void ProvideProxyType(Type resourceType) { - // Step 1: Find the least specific base type that offers the same amount of interfaces + // Step 1: Find the least specific base type that offers the same amount of interfaces and is not a generic itself // ReSharper disable once AssignNullToNotNullAttribute -> FullName should be not null var targetType = _typeCache[resourceType.ResourceType()]; var linker = targetType; var interfaces = RelevantInterfaces(linker); - // Move up the type tree until the parent offers less interfaces than the current linker - while (linker.BaseType != null && interfaces.Count == RelevantInterfaces(linker.BaseType).Count) + // Move up the type tree until the parent offers less interfaces than the current linker, is abstract or a generic + while (linker.BaseType != null && !linker.BaseType.ResourceType.IsGenericType + && interfaces.Count == RelevantInterfaces(linker.BaseType).Count) { linker = linker.BaseType; } + // Step 2: Check if we already created a proxy for this type. If we already // did use this one for the requested type as well. diff --git a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs index ee751b561..d8574ca9b 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/Mocks/ResourceWithGenericMethod.cs @@ -57,4 +57,10 @@ public void RaiseEvent() throw new NotImplementedException(); } } + + public interface IGenericBaseResourceInterface : IResource { } + + public class GenericBaseResource : Resource, IGenericBaseResourceInterface { } + + public class InheritingFromGenericResource : GenericBaseResource { } } diff --git a/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs b/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs index 8ef3f51f7..ccb8a8f9c 100644 --- a/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs +++ b/src/Tests/Moryx.Resources.Management.Tests/TypeControllerTests.cs @@ -222,6 +222,20 @@ public void ProxyBuilderFiltersGenericInterfaces() Assert.IsFalse(typeof(IGenericMethodCall).IsAssignableFrom(proxy.GetType())); } + [Test] + public void ProxyBuilderSkipsGenericBaseTypes() + { + // Arrange + var driver = new InheritingFromGenericResource { Id = 42, Name = "A non generic resource inheriting from a generic base type" }; + + // Act + var proxy = _typeController.GetProxy(driver); + + // Assert + Assert.IsNotNull(proxy); + Assert.IsFalse(typeof(GenericBaseResource).IsAssignableFrom(proxy.GetType())); + } + [Test] public void FacadeExceptionForGenericProxy() {