public ServiceKey(Type serviceType, ServiceDefinition definition) { ServiceType = serviceType; ImplementType = definition.GetImplementType(); }
private object GetServiceInstance(Type serviceType, ServiceDefinition serviceDefinition) { if (serviceDefinition.ImplementationInstance != null) { return(serviceDefinition.ImplementationInstance); } if (serviceDefinition.ImplementationFactory != null) { return(serviceDefinition.ImplementationFactory.Invoke(this)); } var implementType = (serviceDefinition.ImplementType ?? serviceType); if (implementType.IsInterface || implementType.IsAbstract) { throw new InvalidOperationException($"invalid service registered, serviceType: {serviceType.FullName}, implementType: {serviceDefinition.ImplementType}"); } if (implementType.IsGenericType) { implementType = implementType.MakeGenericType(serviceType.GetGenericArguments()); } var newFunc = CacheUtil.TypeNewFuncCache.GetOrAdd(implementType, (serviceContainer) => { if ( CacheUtil.TypeEmptyConstructorFuncCache.TryGetValue(implementType, out var emptyFunc)) { return(emptyFunc.Invoke()); } var ctor = CacheUtil.TypeConstructorCache.GetOrAdd(implementType, t => { var ctorInfos = t.GetConstructors(BindingFlags.Instance | BindingFlags.Public); if (ctorInfos.Length == 0) { return(null); } ConstructorInfo ctorInfo; if (ctorInfos.Length == 1) { ctorInfo = ctorInfos[0]; } else { // TODO: try find best ctor ctorInfo = ctorInfos .OrderBy(_ => _.GetParameters().Length) .First(); } return(ctorInfo); }); if (ctor == null) { throw new InvalidOperationException( $"service {serviceType.FullName} does not have any public constructors"); } var parameters = ctor.GetParameters(); if (parameters.Length == 0) { var func00 = Expression.Lambda <Func <object> >(Expression.New(ctor)).Compile(); CacheUtil.TypeEmptyConstructorFuncCache.TryAdd(implementType, func00); return(func00.Invoke()); } var ctorParams = new object[parameters.Length]; for (var index = 0; index < parameters.Length; index++) { var param = serviceContainer.GetService(parameters[index].ParameterType); if (param == null && parameters[index].HasDefaultValue) { param = parameters[index].DefaultValue; } ctorParams[index] = param; } var func = CacheUtil.TypeConstructorFuncCache.GetOrAdd(implementType, t => { if (!CacheUtil.TypeConstructorCache.TryGetValue(t, out var ctorInfo)) { return(null); } var innerParameters = ctorInfo.GetParameters(); var parameterExpression = Expression.Parameter(typeof(object[]), "arguments"); // create parameter Expression var argExpressions = new Expression[innerParameters.Length]; // array that will contains parameter expessions for (var i = 0; i < innerParameters.Length; i++) { var indexedAccess = Expression.ArrayIndex(parameterExpression, Expression.Constant(i)); if (!innerParameters[i].ParameterType.IsClass) // check if parameter is a value type { var localVariable = Expression.Variable(innerParameters[i].ParameterType, "localVariable"); // if so - we should create local variable that will store paraameter value var block = Expression.Block(new[] { localVariable }, Expression.IfThenElse(Expression.Equal(indexedAccess, Expression.Constant(null)), Expression.Assign(localVariable, Expression.Default(innerParameters[i].ParameterType)), Expression.Assign(localVariable, Expression.Convert(indexedAccess, innerParameters[i].ParameterType)) ), localVariable ); argExpressions[i] = block; } else { argExpressions[i] = Expression.Convert(indexedAccess, innerParameters[i].ParameterType); } } var newExpression = Expression.New(ctorInfo, argExpressions); // create expression that represents call to specified ctor with the specified arguments. return(Expression.Lambda <Func <object[], object> >(newExpression, parameterExpression) .Compile()); }); return(func.Invoke(ctorParams)); }); return(newFunc?.Invoke(this)); }