public Func <ServiceProviderEngineScope, object> Build(ServiceCallSite callSite)
 {
     return(BuildType(callSite).Lambda);
 }
示例#2
0
        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()
            });
        }
示例#5
0
 // 这个方法是访问 Transient 生命周期的方法,可以看到这个方法直接调用 VisitCallSiteMain() 进行获取实例对象,然后调用 CaptureDisposable() 将次对象尝试缓存到 ServiceProviderEngineScope 容器的 _disposables 集合中
 protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
 {
     return(context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context)));
 }
示例#6
0
 // 这个方法是访问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));
 }
示例#7
0
        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));
        }
示例#8
0
 public void Add(Type type, ServiceCallSite serviceCallSite)
 {
     _callSiteCache[type] = serviceCallSite;
 }
示例#9
0
        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));
        }
示例#10
0
 protected override Expression VisitScopeCache(ServiceCallSite callSite, CallSiteExpressionBuilderContext context)
 {
     return(BuildScopedExpression(callSite, context, VisitCallSiteMain(callSite, context)));
 }
示例#11
0
        protected override Expression VisitScopeCache(ServiceCallSite callSite, object context)
        {
            Func <ServiceProviderEngineScope, object> lambda = Build(callSite);

            return(Expression.Invoke(Expression.Constant(lambda), ScopeParameter));
        }
示例#12
0
 protected override Expression VisitRootCache(ServiceCallSite singletonCallSite, object context)
 {
     return(Expression.Constant(_runtimeResolver.Resolve(singletonCallSite, _rootScope)));
 }
示例#13
0
 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));
 }