private ServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot, bool throwOnConstraintViolation) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == descriptor.ServiceType) { ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot); if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite)) { return(serviceCallSite); } 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) { if (throwOnConstraintViolation) { throw; } return(null); } return(_callSiteCache[callSiteKey] = CreateConstructorCallSite(lifetime, serviceType, closedType, callSiteChain)); } return(null); }
private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) { if (serviceType == descriptor.ServiceType) { ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot); if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite)) { return(serviceCallSite); } 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(SR.InvalidServiceDescriptor); } return(_callSiteCache[callSiteKey] = callSite); } return(null); }
private void AddCacheKey(ILEmitResolverBuilderContext argument, ServiceCacheKey key) { // new ServiceCacheKey(typeof(key.Type), key.Slot) argument.Generator.Emit(OpCodes.Ldtoken, key.Type); argument.Generator.Emit(OpCodes.Call, GetTypeFromHandleMethod); argument.Generator.Emit(OpCodes.Ldc_I4, key.Slot); argument.Generator.Emit(OpCodes.Newobj, CacheKeyCtor); }
public ResultCache(ServiceLifetime lifetime, Type type, int slot) { Debug.Assert(lifetime == ServiceLifetime.Transient || type != null); switch (lifetime) { case ServiceLifetime.Singleton: Location = CallSiteResultCacheLocation.Root; break; case ServiceLifetime.Scoped: Location = CallSiteResultCacheLocation.Scope; break; case ServiceLifetime.Transient: Location = CallSiteResultCacheLocation.Dispose; break; default: Location = CallSiteResultCacheLocation.None; break; } Key = new ServiceCacheKey(type, slot); }
private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain) { ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, DefaultSlot); if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite)) { return(serviceCallSite); } 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.Length - 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, callSiteKey); } return(_callSiteCache[callSiteKey] = new IEnumerableCallSite(resultCache, itemType, callSites.ToArray())); } return(null); } finally { callSiteChain.Remove(serviceType); } }
internal ResultCache(CallSiteResultCacheLocation lifetime, ServiceCacheKey cacheKey) { Location = lifetime; Key = cacheKey; }