public Func <ServiceProviderEngineScope, object> Build(ServiceCallSite callSite) { return(BuildType(callSite).Lambda); }
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.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, new ServiceCacheKey(serviceType, DefaultSlot)); } return(new IEnumerableCallSite(resultCache, itemType, callSites.ToArray())); } return(null); } finally { callSiteChain.Remove(serviceType); } }
protected override object VisitRootCache(ServiceCallSite callSite, ILEmitResolverBuilderContext argument) { AddConstant(argument, CallSiteRuntimeResolver.Instance.Resolve(callSite, _rootScope)); return(null); }
private ILEmitResolverBuilderRuntimeContext GenerateMethodBody(ServiceCallSite callSite, ILGenerator generator) { var context = new ILEmitResolverBuilderContext() { Generator = generator, Constants = null, Factories = null }; // if (scope.IsRootScope) // { // return CallSiteRuntimeResolver.Instance.Resolve(callSite, scope); // } // var cacheKey = scopedCallSite.CacheKey; // try // { // var resolvedServices = scope.ResolvedServices; // Monitor.Enter(resolvedServices, out var lockTaken); // if (!resolvedServices.TryGetValue(cacheKey, out value) // { // value = [createvalue]; // CaptureDisposable(value); // resolvedServices.Add(cacheKey, value); // } // } // finally // { // if (lockTaken) Monitor.Exit(scope.ResolvedServices); // } // return value; if (callSite.Cache.Location == CallSiteResultCacheLocation.Scope) { LocalBuilder cacheKeyLocal = context.Generator.DeclareLocal(typeof(ServiceCacheKey)); LocalBuilder resolvedServicesLocal = context.Generator.DeclareLocal(typeof(IDictionary <ServiceCacheKey, object>)); LocalBuilder syncLocal = context.Generator.DeclareLocal(typeof(object)); LocalBuilder lockTakenLocal = context.Generator.DeclareLocal(typeof(bool)); LocalBuilder resultLocal = context.Generator.DeclareLocal(typeof(object)); Label skipCreationLabel = context.Generator.DefineLabel(); Label returnLabel = context.Generator.DefineLabel(); Label defaultLabel = context.Generator.DefineLabel(); // Check if scope IsRootScope context.Generator.Emit(OpCodes.Ldarg_1); context.Generator.Emit(OpCodes.Callvirt, ScopeIsRootScope); context.Generator.Emit(OpCodes.Brfalse_S, defaultLabel); context.Generator.Emit(OpCodes.Call, CallSiteRuntimeResolverInstanceField); AddConstant(context, callSite); context.Generator.Emit(OpCodes.Ldarg_1); context.Generator.Emit(OpCodes.Callvirt, CallSiteRuntimeResolverResolveMethod); context.Generator.Emit(OpCodes.Ret); // Generate cache key context.Generator.MarkLabel(defaultLabel); AddCacheKey(context, callSite.Cache.Key); // and store to local Stloc(context.Generator, cacheKeyLocal.LocalIndex); context.Generator.BeginExceptionBlock(); // scope context.Generator.Emit(OpCodes.Ldarg_1); // .ResolvedServices context.Generator.Emit(OpCodes.Callvirt, ResolvedServicesGetter); // Store resolved services Stloc(context.Generator, resolvedServicesLocal.LocalIndex); // scope context.Generator.Emit(OpCodes.Ldarg_1); // .Sync context.Generator.Emit(OpCodes.Callvirt, ScopeLockGetter); // Store syncLocal Stloc(context.Generator, syncLocal.LocalIndex); // Load syncLocal Ldloc(context.Generator, syncLocal.LocalIndex); // Load address of lockTaken context.Generator.Emit(OpCodes.Ldloca_S, lockTakenLocal.LocalIndex); // Monitor.Enter context.Generator.Emit(OpCodes.Call, ExpressionResolverBuilder.MonitorEnterMethodInfo); // Load resolved services Ldloc(context.Generator, resolvedServicesLocal.LocalIndex); // Load cache key Ldloc(context.Generator, cacheKeyLocal.LocalIndex); // Load address of result local context.Generator.Emit(OpCodes.Ldloca_S, resultLocal.LocalIndex); // .TryGetValue context.Generator.Emit(OpCodes.Callvirt, ExpressionResolverBuilder.TryGetValueMethodInfo); // Jump to the end if already in cache context.Generator.Emit(OpCodes.Brtrue, skipCreationLabel); // Create value VisitCallSiteMain(callSite, context); Stloc(context.Generator, resultLocal.LocalIndex); if (callSite.CaptureDisposable) { BeginCaptureDisposable(context); Ldloc(context.Generator, resultLocal.LocalIndex); EndCaptureDisposable(context); // Pop value returned by CaptureDisposable off the stack generator.Emit(OpCodes.Pop); } // load resolvedServices Ldloc(context.Generator, resolvedServicesLocal.LocalIndex); // load cache key Ldloc(context.Generator, cacheKeyLocal.LocalIndex); // load value Ldloc(context.Generator, resultLocal.LocalIndex); // .Add context.Generator.Emit(OpCodes.Callvirt, ExpressionResolverBuilder.AddMethodInfo); context.Generator.MarkLabel(skipCreationLabel); context.Generator.BeginFinallyBlock(); // load lockTaken Ldloc(context.Generator, lockTakenLocal.LocalIndex); // return if not context.Generator.Emit(OpCodes.Brfalse, returnLabel); // Load syncLocal Ldloc(context.Generator, syncLocal.LocalIndex); // Monitor.Exit context.Generator.Emit(OpCodes.Call, ExpressionResolverBuilder.MonitorExitMethodInfo); context.Generator.MarkLabel(returnLabel); context.Generator.EndExceptionBlock(); // load value Ldloc(context.Generator, resultLocal.LocalIndex); // return context.Generator.Emit(OpCodes.Ret); } else { VisitCallSite(callSite, context); // return context.Generator.Emit(OpCodes.Ret); } return(new ILEmitResolverBuilderRuntimeContext { Constants = context.Constants?.ToArray(), Factories = context.Factories?.ToArray() }); }
// 这个方法是访问 Transient 生命周期的方法,可以看到这个方法直接调用 VisitCallSiteMain() 进行获取实例对象,然后调用 CaptureDisposable() 将次对象尝试缓存到 ServiceProviderEngineScope 容器的 _disposables 集合中 protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context) { return(context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context))); }
// 这个方法是访问Root声明周期的方法,可以看到这个方法调用了一个 VisitCache(),这个方法一共接收四个参数。 // 第一个、第二个分别是当前方法的参数。第三个参数代表容器对象,容器使用的 ServiceProviderEngine 实例中的 Root 属性,这个容器代表了顶级容器。(也就是root生命周期的本质,使用定期容器进行创建/获取实例) // 第四个参数是锁,此方法使用的是 RuntimeResolveLock.Root 锁。 protected override object VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) { return(VisitCache(singletonCallSite, context, context.Scope.Engine.Root, RuntimeResolverLock.Root)); }
private Expression <Func <ServiceProviderEngineScope, object> > BuildExpression(ServiceCallSite callSite) { var context = new CallSiteExpressionBuilderContext { ScopeParameter = ScopeParameter }; var serviceExpression = VisitCallSite(callSite, context); if (context.RequiresResolvedServices) { return(Expression.Lambda <Func <ServiceProviderEngineScope, object> >( Expression.Block( new [] { ResolvedServices }, ResolvedServicesVariableAssignment, Lock(serviceExpression, ResolvedServices)), ScopeParameter)); } return(Expression.Lambda <Func <ServiceProviderEngineScope, object> >(serviceExpression, ScopeParameter)); }
public void Add(Type type, ServiceCallSite serviceCallSite) { _callSiteCache[type] = serviceCallSite; }
private Expression <Func <ServiceProviderEngineScope, object> > BuildExpression(ServiceCallSite callSite) { if (callSite.Cache.Location == CallSiteResultCacheLocation.Scope) { return(Expression.Lambda <Func <ServiceProviderEngineScope, object> >( Expression.Block( new[] { ResolvedServices }, ResolvedServicesVariableAssignment, BuildScopedExpression(callSite)), ScopeParameter)); } return(Expression.Lambda <Func <ServiceProviderEngineScope, object> >( Convert(VisitCallSite(callSite, null), typeof(object), forceValueTypeConversion: true), ScopeParameter)); }
protected override Expression VisitScopeCache(ServiceCallSite callSite, CallSiteExpressionBuilderContext context) { return(BuildScopedExpression(callSite, context, VisitCallSiteMain(callSite, context))); }
protected override Expression VisitScopeCache(ServiceCallSite callSite, object context) { Func <ServiceProviderEngineScope, object> lambda = Build(callSite); return(Expression.Invoke(Expression.Constant(lambda), ScopeParameter)); }
protected override Expression VisitRootCache(ServiceCallSite singletonCallSite, object context) { return(Expression.Constant(_runtimeResolver.Resolve(singletonCallSite, _rootScope))); }
protected override Type?VisitRootCache(ServiceCallSite singletonCallSite, CallSiteValidatorState state) { state.Singleton = singletonCallSite; return(VisitCallSiteMain(singletonCallSite, state)); }
public override Func <ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite);
public override Func <ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite) { return(_expressionResolverBuilder.Build(callSite)); }