Skip to content
This repository was archived by the owner on Nov 2, 2018. It is now read-only.
This repository was archived by the owner on Nov 2, 2018. It is now read-only.

Support constrained open generic types  #471

@jbogard

Description

@jbogard

If I register a collection of open generics, some of the open generics may be constrained. Consider the interface and implementations:

    public interface IFakeOpenGenericService<TValue>
    {
        TValue Value { get; }
    }
    public class FakeOpenGenericService<TVal> : IFakeOpenGenericService<TVal>
    {
        public FakeOpenGenericService(TVal value)
        {
            Value = value;
        }

        public TVal Value { get; }
    }
    public class ConstrainedFakeOpenGenericService<TVal> : IFakeOpenGenericService<TVal> 
        where TVal : PocoClass
    {
        public ConstrainedFakeOpenGenericService(TVal value)
        {
            Value = value;
        }

        public TVal Value { get; }
    }

If I register multiple services:

collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>));
collection.AddTransient(typeof(IFakeOpenGenericService<>), typeof(ConstrainedFakeOpenGenericService<>));

And try to resolve, the version that adheres to all constraints works, but if I try to get a collection with a generic parameter that doesn't match the constraint, I get an exception:

var allServices = provider.GetServices<IFakeOpenGenericService<PocoClass>>().ToList();
var constrainedServices = provider.GetServices<IFakeOpenGenericService<IFakeSingletonService>>().ToList();            

Exception:

      System.ArgumentException : GenericArguments[0], 'Microsoft.Extensions.DependencyInjection.Specification.Fakes.IFakeSingletonService', on 'Microsoft.Extensions.DependencyInjection.Specification.Fakes.ConstrainedFakeOpenGenericService`1[TVal]' violates the constraint of type 'TVal'.
      ---- System.TypeLoadException : GenericArguments[0], 'Microsoft.Extensions.DependencyInjection.Specification.Fakes.IFakeSingletonService', on 'Microsoft.Extensions.DependencyInjection.Specification.Fakes.ConstrainedFakeOpenGenericService`1[TVal]' violates the constraint of type parameter 'TVal'.
      Stack Trace:
           at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
           at System.RuntimeType.MakeGenericType(Type[] instantiation)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\ServiceLookup\GenericService.cs(26,0): at Microsoft.Extensions.DependencyInjection.ServiceLookup.GenericService.GetService(Type closedServiceType)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\ServiceLookup\ServiceTable.cs(102,0): at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceTable.TryGetEntry(Type serviceType, ServiceEntry& entry)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\ServiceLookup\OpenIEnumerableService.cs(28,0): at Microsoft.Extensions.DependencyInjection.ServiceLookup.OpenIEnumerableService.GetService(Type closedServiceType)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\ServiceLookup\ServiceTable.cs(102,0): at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceTable.TryGetEntry(Type serviceType, ServiceEntry& entry)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\ServiceProvider.cs(114,0): at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetServiceCallSite(Type serviceType, ISet`1 callSiteChain)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\ServiceProvider.cs(73,0): at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType, ServiceProvider serviceProvider)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\Internal\ConcurrentDictionaryExtensions.cs(24,0): at System.Collections.Concurrent.ConcurrentDictionaryExtensions.GetOrAdd[TKey,TValue,TArg](ConcurrentDictionary`2 dictionary, TKey key, Func`3 valueFactory, TArg arg)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection\ServiceProvider.cs(64,0): at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection.Abstractions\ServiceProviderServiceExtensions.cs(56,0): at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection.Abstractions\ServiceProviderServiceExtensions.cs(79,0): at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection.Abstractions\ServiceProviderServiceExtensions.cs(95,0): at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetServices[T](IServiceProvider provider)
        C:\dev\aspnet-DependencyInjection\src\Microsoft.Extensions.DependencyInjection.Specification.Tests\DependencyInjectionSpecificationTests.cs(561,0): at Microsoft.Extensions.DependencyInjection.Specification.DependencyInjectionSpecificationTests.ConstrainedOpenGenericServicesCanBeResolved()
        ----- Inner Stack Trace -----
           at System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle handle, IntPtr* pInst, Int32 numGenericArgs, ObjectHandleOnStack type)
           at System.RuntimeTypeHandle.Instantiate(Type[] inst)
           at System.RuntimeType.MakeGenericType(Type[] instantiation)

Expected: constrained open generics are tested before attempted to instantiate. It looks like the only way to reliably test is to try-catch-swallow, see http://stackoverflow.com/a/4864565/58508

PR with failing test coming shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions