From 0a6acf35b4165f14b0b667f64b0fda77484544bf Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Thu, 16 Jul 2020 22:08:55 -0700 Subject: [PATCH] Revert "Adding support for constrained open generics to DI (#34393)" (#39486) This reverts commit 211bc884dbadb8765699554257699f5c82d21f6d. --- .../src/Resources/Strings.resx | 3 - .../src/ServiceLookup/CallSiteFactory.cs | 22 +- .../tests/DI.External.Tests/Autofac.cs | 9 +- .../tests/DI.External.Tests/StashBox.cs | 11 +- .../DependencyInjectionSpecificationTests.cs | 154 ----------- .../DI.Specification.Tests/Fakes/AbstractClass.cs | 10 - .../Fakes/ClassImplementingIComparable.cs | 13 - .../Fakes/ClassImplementingIEnumerable.cs | 14 - .../Fakes/ClassInheritingAbstractClass.cs | 21 -- .../Fakes/ClassWithAbstractClassConstraint.cs | 14 - .../Fakes/ClassWithClassConstraint.cs | 12 - .../Fakes/ClassWithInterfaceConstraint.cs | 16 -- .../Fakes/ClassWithNewConstraint.cs | 12 - .../Fakes/ClassWithNoConstraint.cs | 11 - .../Fakes/ClassWithSelfReferencingConstraint.cs | 16 -- .../Fakes/ClassWithStructConstraint.cs | 12 - .../Fakes/ConstrainedFakeOpenGenericService.cs | 16 -- .../Fakes/IFakeOpenGenericService.cs | 2 +- .../tests/DI.Tests/Fakes/AbstractClass.cs | 12 + .../DI.Tests/ServiceLookup/CallSiteFactoryTest.cs | 293 --------------------- 20 files changed, 21 insertions(+), 652 deletions(-) delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AbstractClass.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIComparable.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIEnumerable.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassInheritingAbstractClass.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAbstractClassConstraint.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithClassConstraint.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInterfaceConstraint.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNewConstraint.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNoConstraint.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithSelfReferencingConstraint.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStructConstraint.cs delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ConstrainedFakeOpenGenericService.cs create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/AbstractClass.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Resources/Strings.resx index 134d98f..354fe5f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Resources/Strings.resx @@ -159,7 +159,4 @@ '{0}' type only implements IAsyncDisposable. Use DisposeAsync to dispose the container. - - Generic constraints violated for type '{0}' while attempting to activate '{1}'. - \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs index 9adc47d..2bf5ee1 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs @@ -118,7 +118,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup if (serviceType.IsConstructedGenericType && _descriptorLookup.TryGetValue(serviceType.GetGenericTypeDefinition(), out ServiceDescriptorCacheItem descriptor)) { - return TryCreateOpenGeneric(descriptor.Last, serviceType, callSiteChain, DefaultSlot, true); + return TryCreateOpenGeneric(descriptor.Last, serviceType, callSiteChain, DefaultSlot); } return null; @@ -164,7 +164,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { ServiceDescriptor descriptor = _descriptors[i]; ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ?? - TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot, false); + TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot); if (callSite != null) { @@ -230,28 +230,14 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup return null; } - private ServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot, bool throwOnConstraintViolation) + private ServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == descriptor.ServiceType) { Debug.Assert(descriptor.ImplementationType != null, "descriptor.ImplementationType != null"); var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot); - Type closedType; - try - { - closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments); - } - catch (ArgumentException ex) - { - if (throwOnConstraintViolation) - { - throw new InvalidOperationException(SR.Format(SR.GenericConstraintViolation, serviceType, descriptor.ImplementationType), ex); - } - - return null; - } - + Type closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments); return CreateConstructorCallSite(lifetime, serviceType, closedType, callSiteChain); } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Autofac.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Autofac.cs index ccb31e1..1529598 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Autofac.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Autofac.cs @@ -7,14 +7,9 @@ using Autofac.Extensions.DependencyInjection; namespace Microsoft.Extensions.DependencyInjection.Specification { - public class AutofacDependencyInjectionSpecificationTests : SkippableDependencyInjectionSpecificationTests + public class AutofacDependencyInjectionSpecificationTests: DependencyInjectionSpecificationTests { - public override string[] SkippedTests => new[] - { - "PublicNoArgCtorConstrainedOpenGenericServicesCanBeResolved" - }; - - protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection) + protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { var builder = new ContainerBuilder(); builder.Populate(serviceCollection); diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StashBox.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StashBox.cs index 6298663..28a27f0 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StashBox.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StashBox.cs @@ -5,16 +5,9 @@ using System; namespace Microsoft.Extensions.DependencyInjection.Specification { - public class StashBoxDependencyInjectionSpecificationTests : SkippableDependencyInjectionSpecificationTests + public class StashBoxDependencyInjectionSpecificationTests: DependencyInjectionSpecificationTests { - public override string[] SkippedTests => new[] - { - "PublicNoArgCtorConstrainedOpenGenericServicesCanBeResolved", - "SelfReferencingConstrainedOpenGenericServicesCanBeResolved", - "ClassConstrainedOpenGenericServicesCanBeResolved" - }; - - protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection) + protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { return serviceCollection.UseStashbox(); } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs index 9d82878..e50d9ca 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs @@ -592,160 +592,6 @@ namespace Microsoft.Extensions.DependencyInjection.Specification } [Fact] - public void ConstrainedOpenGenericServicesCanBeResolved() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ConstrainedFakeOpenGenericService<>)); - var poco = new PocoClass(); - collection.AddSingleton(poco); - collection.AddSingleton(); - var provider = CreateServiceProvider(collection); - // Act - var allServices = provider.GetServices>().ToList(); - var constrainedServices = provider.GetServices>().ToList(); - var singletonService = provider.GetService(); - // Assert - Assert.Equal(2, allServices.Count); - Assert.Same(poco, allServices[0].Value); - Assert.Same(poco, allServices[1].Value); - Assert.Equal(1, constrainedServices.Count); - Assert.Same(singletonService, constrainedServices[0].Value); - } - - [Fact] - public void ConstrainedOpenGenericServicesReturnsEmptyWithNoMatches() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ConstrainedFakeOpenGenericService<>)); - collection.AddSingleton(); - var provider = CreateServiceProvider(collection); - // Act - var constrainedServices = provider.GetServices>().ToList(); - // Assert - Assert.Equal(0, constrainedServices.Count); - } - - [Fact] - public void InterfaceConstrainedOpenGenericServicesCanBeResolved() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithInterfaceConstraint<>)); - var enumerableVal = new ClassImplementingIEnumerable(); - collection.AddSingleton(enumerableVal); - collection.AddSingleton(); - var provider = CreateServiceProvider(collection); - // Act - var allServices = provider.GetServices>().ToList(); - var constrainedServices = provider.GetServices>().ToList(); - var singletonService = provider.GetService(); - // Assert - Assert.Equal(2, allServices.Count); - Assert.Same(enumerableVal, allServices[0].Value); - Assert.Same(enumerableVal, allServices[1].Value); - Assert.Equal(1, constrainedServices.Count); - Assert.Same(singletonService, constrainedServices[0].Value); - } - - [Fact] - public void PublicNoArgCtorConstrainedOpenGenericServicesCanBeResolved() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithNoConstraints<>)); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithNewConstraint<>)); - var provider = CreateServiceProvider(collection); - // Act - var allServices = provider.GetServices>().ToList(); - var constrainedServices = provider.GetServices>().ToList(); - // Assert - Assert.Equal(2, allServices.Count); - Assert.Equal(1, constrainedServices.Count); - } - - [Fact] - public void ClassConstrainedOpenGenericServicesCanBeResolved() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithNoConstraints<>)); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithClassConstraint<>)); - var provider = CreateServiceProvider(collection); - // Act - var allServices = provider.GetServices>().ToList(); - var constrainedServices = provider.GetServices>().ToList(); - // Assert - Assert.Equal(2, allServices.Count); - Assert.Equal(1, constrainedServices.Count); - } - - [Fact] - public void StructConstrainedOpenGenericServicesCanBeResolved() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithNoConstraints<>)); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithStructConstraint<>)); - var provider = CreateServiceProvider(collection); - // Act - var allServices = provider.GetServices>().ToList(); - var constrainedServices = provider.GetServices>().ToList(); - // Assert - Assert.Equal(2, allServices.Count); - Assert.Equal(1, constrainedServices.Count); - } - - [Fact] - public void AbstractClassConstrainedOpenGenericServicesCanBeResolved() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithAbstractClassConstraint<>)); - var poco = new PocoClass(); - collection.AddSingleton(poco); - var classInheritingClassInheritingAbstractClass = new ClassInheritingClassInheritingAbstractClass(); - collection.AddSingleton(classInheritingClassInheritingAbstractClass); - var provider = CreateServiceProvider(collection); - // Act - var allServices = provider.GetServices>().ToList(); - var constrainedServices = provider.GetServices>().ToList(); - // Assert - Assert.Equal(2, allServices.Count); - Assert.Same(classInheritingClassInheritingAbstractClass, allServices[0].Value); - Assert.Same(classInheritingClassInheritingAbstractClass, allServices[1].Value); - Assert.Equal(1, constrainedServices.Count); - Assert.Same(poco, constrainedServices[0].Value); - } - - [Fact] - public void SelfReferencingConstrainedOpenGenericServicesCanBeResolved() - { - // Arrange - var collection = new TestServiceCollection(); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); - collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ClassWithSelfReferencingConstraint<>)); - var poco = new PocoClass(); - collection.AddSingleton(poco); - var selfComparable = new ClassImplementingIComparable(); - collection.AddSingleton(selfComparable); - var provider = CreateServiceProvider(collection); - // Act - var allServices = provider.GetServices>().ToList(); - var constrainedServices = provider.GetServices>().ToList(); - // Assert - Assert.Equal(2, allServices.Count); - Assert.Same(selfComparable, allServices[0].Value); - Assert.Same(selfComparable, allServices[1].Value); - Assert.Equal(1, constrainedServices.Count); - Assert.Same(poco, constrainedServices[0].Value); - } - - [Fact] public void ClosedServicesPreferredOverOpenGenericServices() { // Arrange diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AbstractClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AbstractClass.cs deleted file mode 100644 index 412a042..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/AbstractClass.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public abstract class AbstractClass - { - - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIComparable.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIComparable.cs deleted file mode 100644 index 02ffe2e..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIComparable.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassImplementingIComparable : IComparable - { - public int CompareTo(ClassImplementingIComparable other) => 0; - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIEnumerable.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIEnumerable.cs deleted file mode 100644 index 20fe4e2..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassImplementingIEnumerable.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections; - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassImplementingIEnumerable : IEnumerable - { - public IEnumerator GetEnumerator() => throw new NotImplementedException(); - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassInheritingAbstractClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassInheritingAbstractClass.cs deleted file mode 100644 index ec37f2b..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassInheritingAbstractClass.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassInheritingAbstractClass : AbstractClass - { - - } - - public class ClassAlsoInheritingAbstractClass : AbstractClass - { - - } - - public class ClassInheritingClassInheritingAbstractClass : ClassInheritingAbstractClass - { - - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAbstractClassConstraint.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAbstractClassConstraint.cs deleted file mode 100644 index e551986..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithAbstractClassConstraint.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassWithAbstractClassConstraint : IFakeOpenGenericService - where T : AbstractClass - { - public ClassWithAbstractClassConstraint(T value) => Value = value; - - public T Value { get; } - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithClassConstraint.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithClassConstraint.cs deleted file mode 100644 index b180203..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithClassConstraint.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassWithClassConstraint : IFakeOpenGenericService - where T : class - { - public T Value { get; } = default; - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInterfaceConstraint.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInterfaceConstraint.cs deleted file mode 100644 index efd2c9c..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithInterfaceConstraint.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections; - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassWithInterfaceConstraint : IFakeOpenGenericService - where T : IEnumerable - { - public ClassWithInterfaceConstraint(T value) => Value = value; - - public T Value { get; } - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNewConstraint.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNewConstraint.cs deleted file mode 100644 index 143986c..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNewConstraint.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassWithNewConstraint : IFakeOpenGenericService - where T : new() - { - public T Value { get; } = new T(); - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNoConstraint.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNoConstraint.cs deleted file mode 100644 index 848e755..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithNoConstraint.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassWithNoConstraints : IFakeOpenGenericService - { - public T Value { get; } = default; - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithSelfReferencingConstraint.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithSelfReferencingConstraint.cs deleted file mode 100644 index 0e46429..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithSelfReferencingConstraint.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassWithSelfReferencingConstraint : IFakeOpenGenericService - where T : IComparable - { - public ClassWithSelfReferencingConstraint(T value) => Value = value; - - public T Value { get; } - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStructConstraint.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStructConstraint.cs deleted file mode 100644 index 06355eb..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithStructConstraint.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ClassWithStructConstraint : IFakeOpenGenericService - where T : struct - { - public T Value { get; } = default; - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ConstrainedFakeOpenGenericService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ConstrainedFakeOpenGenericService.cs deleted file mode 100644 index 940e362..0000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ConstrainedFakeOpenGenericService.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes -{ - public class ConstrainedFakeOpenGenericService : IFakeOpenGenericService - where TVal : PocoClass - { - public ConstrainedFakeOpenGenericService(TVal value) - { - Value = value; - } - public TVal Value { get; } - } -} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs index d556939..7187035 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/IFakeOpenGenericService.cs @@ -3,7 +3,7 @@ namespace Microsoft.Extensions.DependencyInjection.Specification.Fakes { - public interface IFakeOpenGenericService + public interface IFakeOpenGenericService { TValue Value { get; } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/AbstractClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/AbstractClass.cs new file mode 100644 index 0000000..b2d1cff --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/AbstractClass.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Extensions.DependencyInjection.Tests.Fakes +{ + public abstract class AbstractClass + { + public AbstractClass() + { + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/CallSiteFactoryTest.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/CallSiteFactoryTest.cs index b8d8e6a..bc0988f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/CallSiteFactoryTest.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/CallSiteFactoryTest.cs @@ -111,299 +111,6 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup Assert.Empty(ctorCallSite.ParameterCallSites); } - [Fact] - public void CreateCallSite_Throws_IfClosedTypeDoesNotSatisfyStructGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithStructConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var nonMatchingType = typeof(IFakeOpenGenericService); - // Assert - var ex = Assert.Throws(() => callSiteFactory(nonMatchingType)); - Assert.Equal($"Generic constraints violated for type '{nonMatchingType}' while attempting to activate '{implementationType}'.", ex.Message); - } - - [Fact] - public void CreateCallSite_ReturnsService_IfClosedTypeSatisfiesStructGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithStructConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var matchingType = typeof(IFakeOpenGenericService); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - Assert.NotNull(matchingCallSite); - } - - [Fact] - public void CreateCallSite_Throws_IfClosedTypeDoesNotSatisfyClassGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithClassConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var nonMatchingType = typeof(IFakeOpenGenericService); - // Assert - var ex = Assert.Throws(() => callSiteFactory(nonMatchingType)); - Assert.Equal($"Generic constraints violated for type '{nonMatchingType}' while attempting to activate '{implementationType}'.", ex.Message); - } - - [Fact] - public void CreateCallSite_ReturnsService_IfClosedTypeSatisfiesClassGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithClassConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var matchingType = typeof(IFakeOpenGenericService); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - Assert.NotNull(matchingCallSite); - } - - [Fact] - public void CreateCallSite_Throws_IfClosedTypeDoesNotSatisfyNewGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithNewConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var nonMatchingType = typeof(IFakeOpenGenericService); - // Assert - var ex = Assert.Throws(() => callSiteFactory(nonMatchingType)); - Assert.Equal($"Generic constraints violated for type '{nonMatchingType}' while attempting to activate '{implementationType}'.", ex.Message); - } - - [Fact] - public void CreateCallSite_ReturnsService_IfClosedTypeSatisfiesNewGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithNewConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor, new ServiceDescriptor(typeof(TypeWithParameterlessPublicConstructor), new TypeWithParameterlessPublicConstructor())); - // Act - var matchingType = typeof(IFakeOpenGenericService); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - Assert.NotNull(matchingCallSite); - } - - [Fact] - public void CreateCallSite_Throws_IfClosedTypeDoesNotSatisfyInterfaceGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithInterfaceConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var nonMatchingType = typeof(IFakeOpenGenericService); - // Assert - var ex = Assert.Throws(() => callSiteFactory(nonMatchingType)); - Assert.Equal($"Generic constraints violated for type '{nonMatchingType}' while attempting to activate '{implementationType}'.", ex.Message); - } - - [Fact] - public void CreateCallSite_ReturnsService_IfClosedTypeSatisfiesInterfaceGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithInterfaceConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor, new ServiceDescriptor(typeof(string), "")); - // Act - var matchingType = typeof(IFakeOpenGenericService); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - Assert.NotNull(matchingCallSite); - } - - [Fact] - public void CreateCallSite_Throws_IfClosedTypeDoesNotSatisfyAbstractClassGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithAbstractClassConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var nonMatchingType = typeof(IFakeOpenGenericService); - // Assert - var ex = Assert.Throws(() => callSiteFactory(nonMatchingType)); - Assert.Equal($"Generic constraints violated for type '{nonMatchingType}' while attempting to activate '{implementationType}'.", ex.Message); - } - - [Fact] - public void CreateCallSite_ReturnsService_IfClosedTypeSatisfiesAbstractClassGenericConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithAbstractClassConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor, new ServiceDescriptor(typeof(ClassInheritingAbstractClass), new ClassInheritingAbstractClass())); - // Act - var matchingType = typeof(IFakeOpenGenericService); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - Assert.NotNull(matchingCallSite); - } - - [Fact] - public void CreateCallSite_Throws_IfClosedTypeDoesNotSatisfySelfReferencingConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithSelfReferencingConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var nonMatchingType = typeof(IFakeOpenGenericService); - // Assert - var ex = Assert.Throws(() => callSiteFactory(nonMatchingType)); - Assert.Equal($"Generic constraints violated for type '{nonMatchingType}' while attempting to activate '{implementationType}'.", ex.Message); - } - - [Fact] - public void CreateCallSite_Throws_IfComplexClosedTypeDoesNotSatisfySelfReferencingConstraint() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithSelfReferencingConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor); - // Act - var nonMatchingType = typeof(IFakeOpenGenericService); - // Assert - var ex = Assert.Throws(() => callSiteFactory(nonMatchingType)); - Assert.Equal($"Generic constraints violated for type '{nonMatchingType}' while attempting to activate '{implementationType}'.", ex.Message); - } - - [Fact] - public void CreateCallSite_ReturnsService_IfClosedTypeSatisfiesSelfReferencing() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var implementationType = typeof(ClassWithSelfReferencingConstraint<>); - var descriptor = new ServiceDescriptor(serviceType, implementationType, ServiceLifetime.Transient); - var callSiteFactory = GetCallSiteFactory(descriptor, new ServiceDescriptor(typeof(string), "")); - // Act - var matchingType = typeof(IFakeOpenGenericService); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - Assert.NotNull(matchingCallSite); - } - - [Fact] - public void CreateCallSite_ReturnsEmpty_IfClosedTypeSatisfiesBaseClassConstraintButRegisteredTypeNotExactMatch() - { - // Arrange - var classInheritingAbstractClassImplementationType = typeof(ClassWithAbstractClassConstraint); - var classInheritingAbstractClassDescriptor = new ServiceDescriptor(typeof(IFakeOpenGenericService), classInheritingAbstractClassImplementationType, ServiceLifetime.Transient); - var classAlsoInheritingAbstractClassImplementationType = typeof(ClassWithAbstractClassConstraint); - var classAlsoInheritingAbstractClassDescriptor = new ServiceDescriptor(typeof(IFakeOpenGenericService), classAlsoInheritingAbstractClassImplementationType, ServiceLifetime.Transient); - var classInheritingClassInheritingAbstractClassImplementationType = typeof(ClassWithAbstractClassConstraint); - var classInheritingClassInheritingAbstractClassDescriptor = new ServiceDescriptor(typeof(IFakeOpenGenericService), classInheritingClassInheritingAbstractClassImplementationType, ServiceLifetime.Transient); - var notMatchingServiceType = typeof(IFakeOpenGenericService); - var notMatchingType = typeof(FakeService); - var notMatchingDescriptor = new ServiceDescriptor(notMatchingServiceType, notMatchingType, ServiceLifetime.Transient); - - var callSiteFactory = GetCallSiteFactory(classInheritingAbstractClassDescriptor, classAlsoInheritingAbstractClassDescriptor, classInheritingClassInheritingAbstractClassDescriptor, notMatchingDescriptor); - // Act - var matchingType = typeof(IEnumerable>); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - var enumerableCall = Assert.IsType(matchingCallSite); - - Assert.Empty(enumerableCall.ServiceCallSites); - } - - [Fact] - public void CreateCallSite_ReturnsMatchingTypes_IfClosedTypeSatisfiesBaseClassConstraintAndRegisteredType() - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService); - var classInheritingAbstractClassImplementationType = typeof(ClassWithAbstractClassConstraint); - var classInheritingAbstractClassDescriptor = new ServiceDescriptor(serviceType, classInheritingAbstractClassImplementationType, ServiceLifetime.Transient); - var classAlsoInheritingAbstractClassImplementationType = typeof(ClassWithAbstractClassConstraint); - var classAlsoInheritingAbstractClassDescriptor = new ServiceDescriptor(serviceType, classAlsoInheritingAbstractClassImplementationType, ServiceLifetime.Transient); - var classInheritingClassInheritingAbstractClassImplementationType = typeof(ClassWithAbstractClassConstraint); - var classInheritingClassInheritingAbstractClassDescriptor = new ServiceDescriptor(serviceType, classInheritingClassInheritingAbstractClassImplementationType, ServiceLifetime.Transient); - var notMatchingServiceType = typeof(IFakeOpenGenericService); - var notMatchingType = typeof(FakeService); - var notMatchingDescriptor = new ServiceDescriptor(notMatchingServiceType, notMatchingType, ServiceLifetime.Transient); - - var descriptors = new[] - { - classInheritingAbstractClassDescriptor, - new ServiceDescriptor(typeof(ClassInheritingAbstractClass), new ClassInheritingAbstractClass()), - classAlsoInheritingAbstractClassDescriptor, - new ServiceDescriptor(typeof(ClassAlsoInheritingAbstractClass), new ClassAlsoInheritingAbstractClass()), - classInheritingClassInheritingAbstractClassDescriptor, - new ServiceDescriptor(typeof(ClassInheritingClassInheritingAbstractClass), new ClassInheritingClassInheritingAbstractClass()), - notMatchingDescriptor - }; - var callSiteFactory = GetCallSiteFactory(descriptors); - // Act - var matchingType = typeof(IEnumerable<>).MakeGenericType(serviceType); - var matchingCallSite = callSiteFactory(matchingType); - // Assert - var enumerableCall = Assert.IsType(matchingCallSite); - - var matchingTypes = new[] - { - classInheritingAbstractClassImplementationType, - classAlsoInheritingAbstractClassImplementationType, - classInheritingClassInheritingAbstractClassImplementationType - }; - Assert.Equal(matchingTypes.Length, enumerableCall.ServiceCallSites.Length); - Assert.Equal(matchingTypes, enumerableCall.ServiceCallSites.Select(scs => scs.ImplementationType).ToArray()); - } - - [Theory] - [InlineData(typeof(IFakeOpenGenericService), default(int), new[] { typeof(FakeOpenGenericService), typeof(ClassWithStructConstraint), typeof(ClassWithNewConstraint), typeof(ClassWithSelfReferencingConstraint) })] - [InlineData(typeof(IFakeOpenGenericService), "", new[] { typeof(FakeOpenGenericService), typeof(ClassWithClassConstraint), typeof(ClassWithInterfaceConstraint), typeof(ClassWithSelfReferencingConstraint) })] - [InlineData(typeof(IFakeOpenGenericService), new[] { 1, 2, 3 }, new[] { typeof(FakeOpenGenericService), typeof(ClassWithClassConstraint), typeof(ClassWithInterfaceConstraint) })] - public void CreateCallSite_ReturnsMatchingTypesThatMatchCorrectConstraints(Type closedServiceType, object value, Type[] matchingImplementationTypes) - { - // Arrange - var serviceType = typeof(IFakeOpenGenericService<>); - var noConstraintImplementationType = typeof(FakeOpenGenericService<>); - var noConstraintDescriptor = new ServiceDescriptor(serviceType, noConstraintImplementationType, ServiceLifetime.Transient); - var structImplementationType = typeof(ClassWithStructConstraint<>); - var structDescriptor = new ServiceDescriptor(serviceType, structImplementationType, ServiceLifetime.Transient); - var classImplementationType = typeof(ClassWithClassConstraint<>); - var classDescriptor = new ServiceDescriptor(serviceType, classImplementationType, ServiceLifetime.Transient); - var newImplementationType = typeof(ClassWithNewConstraint<>); - var newDescriptor = new ServiceDescriptor(serviceType, newImplementationType, ServiceLifetime.Transient); - var interfaceImplementationType = typeof(ClassWithInterfaceConstraint<>); - var interfaceDescriptor = new ServiceDescriptor(serviceType, interfaceImplementationType, ServiceLifetime.Transient); - var selfConstraintImplementationType = typeof(ClassWithSelfReferencingConstraint<>); - var selfConstraintDescriptor = new ServiceDescriptor(serviceType, selfConstraintImplementationType, ServiceLifetime.Transient); - var serviceValueType = closedServiceType.GenericTypeArguments[0]; - var serviceValueDescriptor = new ServiceDescriptor(serviceValueType, value); - var callSiteFactory = GetCallSiteFactory(noConstraintDescriptor, structDescriptor, classDescriptor, newDescriptor, interfaceDescriptor, selfConstraintDescriptor, serviceValueDescriptor); - var collectionType = typeof(IEnumerable<>).MakeGenericType(closedServiceType); - // Act - var callSite = callSiteFactory(collectionType); - // Assert - var enumerableCall = Assert.IsType(callSite); - Assert.Equal(matchingImplementationTypes.Length, enumerableCall.ServiceCallSites.Length); - Assert.Equal(matchingImplementationTypes, enumerableCall.ServiceCallSites.Select(scs => scs.ImplementationType).ToArray()); - } - public static TheoryData CreateCallSite_PicksConstructorWithTheMostNumberOfResolvedParametersData => new TheoryData, Type[]> { -- 2.7.4