diff --git a/src/StreamJsonRpc/Reflection/ProxyBase.cs b/src/StreamJsonRpc/Reflection/ProxyBase.cs index 393aa37a..0d188d88 100644 --- a/src/StreamJsonRpc/Reflection/ProxyBase.cs +++ b/src/StreamJsonRpc/Reflection/ProxyBase.cs @@ -381,22 +381,17 @@ private static bool ProxyImplementsCompatibleSetOfInterfaces( JsonRpcProxyOptions? options) { HashSet proxyInterfaces = [.. proxyClass.GetInterfaces()]; - if (!proxyInterfaces.Remove(contractInterface)) - { - return false; - } - foreach (Type addl in additionalContractInterfaces) + // Put all the interfaces required into a set so that duplicates are removed. + HashSet requiredInterfaces = [contractInterface, .. additionalContractInterfaces]; + foreach ((Type addl, _) in implementedOptionalInterfaces) { - if (!proxyInterfaces.Remove(addl)) - { - return false; - } + requiredInterfaces.Add(addl); } - foreach ((Type addl, _) in implementedOptionalInterfaces) + foreach (Type reqd in requiredInterfaces) { - if (!proxyInterfaces.Remove(addl)) + if (!proxyInterfaces.Remove(reqd)) { return false; } @@ -421,22 +416,35 @@ private static bool ProxyImplementsCompatibleSetOfInterfaces( continue; } + bool ok = false; foreach (Type addl in additionalContractInterfaces) { if (remaining.IsAssignableFrom(addl)) { + ok = true; continue; } } + if (ok) + { + continue; + } + foreach ((Type addl, _) in implementedOptionalInterfaces) { if (remaining.IsAssignableFrom(addl)) { + ok = true; continue; } } + if (ok) + { + continue; + } + // This is an extra, unwanted interface. return false; } diff --git a/src/StreamJsonRpc/Reflection/ProxyInputs.cs b/src/StreamJsonRpc/Reflection/ProxyInputs.cs index bda0211d..be98bad3 100644 --- a/src/StreamJsonRpc/Reflection/ProxyInputs.cs +++ b/src/StreamJsonRpc/Reflection/ProxyInputs.cs @@ -67,7 +67,7 @@ internal ProxyInputs(ProxyInputs copyFrom) /// /// Gets a description of the requirements on the proxy to be used. /// - internal string Requirements => $"Implementing interface(s): {string.Join(", ", [this.ContractInterface, .. this.AdditionalContractInterfaces.Span])}."; + internal string Requirements => $"Implementing interface(s): {string.Join(", ", [this.ContractInterface, .. this.AdditionalContractInterfaces.Span])}"; /// /// Sorts so that: diff --git a/test/StreamJsonRpc.Tests/JsonRpcProxyGenerationTests.cs b/test/StreamJsonRpc.Tests/JsonRpcProxyGenerationTests.cs index e12857aa..511085dc 100644 --- a/test/StreamJsonRpc.Tests/JsonRpcProxyGenerationTests.cs +++ b/test/StreamJsonRpc.Tests/JsonRpcProxyGenerationTests.cs @@ -997,9 +997,11 @@ private static void DynamicAssembliesKeyedByAssemblyLoadContext_Helper(JsonRpcPr #if NO_INTERCEPTORS public class Dynamic(ITestOutputHelper logger) : JsonRpcProxyGenerationTests(logger, JsonRpcProxyOptions.ProxyImplementation.AlwaysDynamic); -#else +#endif + public class SourceGenerated(ITestOutputHelper logger) : JsonRpcProxyGenerationTests(logger, JsonRpcProxyOptions.ProxyImplementation.AlwaysSourceGenerated) { +#if !NO_INTERCEPTORS /// /// The interceptor cannot fallback to dynamic proxies at runtime when the Options demands it, /// because doing so would generate linker warnings for NativeAOT apps. @@ -1066,9 +1068,8 @@ public async Task CheckedInProxiesFromPastGenerationsStillWork() Assert.Equal(0, failures); } - } - #endif + } public class EmptyClass {