private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) { if (serviceType == descriptor.ServiceType) { ServiceCallSite callSite; var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot); if (descriptor.ImplementationInstance != null) { callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance); } else if (descriptor.ImplementationFactory != null) { callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory); } else if (descriptor.ImplementationType != null) { callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain); } else { throw new InvalidOperationException("Invalid service descriptor"); } return(callSite); } return(null); }
private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain) { try { callSiteChain.Add(serviceType); if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable <>)) { Type itemType = serviceType.GenericTypeArguments[0]; CallSiteResultCacheLocation cacheLocation = CallSiteResultCacheLocation.Root; var callSites = new List <ServiceCallSite>(); // If item type is not generic we can safely use descriptor cache if (!itemType.IsConstructedGenericType && _descriptorLookup.TryGetValue(itemType, out ServiceDescriptorCacheItem descriptors)) { for (int i = 0; i < descriptors.Count; i++) { ServiceDescriptor descriptor = descriptors[i]; // Last service should get slot 0 int slot = descriptors.Count - i - 1; // There may not be any open generics here ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot); Debug.Assert(callSite != null); cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location); callSites.Add(callSite); } } else { int slot = 0; // We are going in reverse so the last service in descriptor list gets slot 0 for (int i = _descriptors.Count - 1; i >= 0; i--) { ServiceDescriptor descriptor = _descriptors[i]; ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ?? TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot, false); if (callSite != null) { slot++; cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location); callSites.Add(callSite); } } callSites.Reverse(); } ResultCache resultCache = ResultCache.None; if (cacheLocation == CallSiteResultCacheLocation.Scope || cacheLocation == CallSiteResultCacheLocation.Root) { resultCache = new ResultCache(cacheLocation, new ServiceCacheKey(serviceType, DefaultSlot)); } return(new IEnumerableCallSite(resultCache, itemType, callSites.ToArray())); } return(null); } finally { callSiteChain.Remove(serviceType); } }