/// <summary> /// Tracks the specified <paramref name="instance"/> for disposation. /// </summary> /// <param name="resolveContext">the resolver context from which the service was resolved</param> /// <param name="instance">the instance to track</param> /// <param name="scopeKey"> /// the <paramref name="scopeKey"/> the instance was created for; if /// <see langword="null"/> then the scope is global. /// </param> public void TrackInstance(ServiceResolveContext resolveContext, object instance, object scopeKey = null) { // check if the tracking of disposable transients is enabled if (!resolveContext.Resolver.TrackDisposableTransients) { return; } // The instances in the lifetime are tracked to dispose them, so we need only to track // disposable / asynchronously disposable objects. #if SUPPORTS_ASYNC_DISPOSABLE // check if the instance does not inherit from IDisposable or IAsyncDisposable, then // there is no need to track the service instance since the transient lifetime always // re-creates services if (!(instance is IDisposable || instance is IAsyncDisposable)) { // there is no need to track the instance return; } // acquire lock _trackerLock.Wait(); // ensure the lock is released even if an exception is thrown try { // track instance _tracker.Add(instance); } finally { // release lock and let other threads continue _trackerLock.Release(); } #else // SUPPORTS_ASYNC_DISPOSABLE if (instance is IDisposable disposable) { lock (_trackerLock) { // add instance to tracking list _tracker.Add(disposable); } } #endif // !SUPPORTS_ASYNC_DISPOSABLE }
/// <summary> /// Creates a new instance of the specified service type (in <paramref name="context"/>). /// </summary> /// <param name="implementationType">the type of the implementation to construct</param> /// <param name="context">the resolve context</param> /// <returns>the service instance</returns> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="implementationType"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="context"/> is <see langword="null"/>. /// </exception> public static object Resolve(Type implementationType, ServiceResolveContext context) { // TODO add parameter for service construction mode if (implementationType is null) { throw new ArgumentNullException(nameof(implementationType)); } if (context is null) { throw new ArgumentNullException(nameof(context)); } // resolve constructors #if SUPPORTS_REFLECTION var availableConstructors = implementationType.GetConstructors(); #else // SUPPORTS_REFLECTION var availableConstructors = implementationType.GetTypeInfo().DeclaredConstructors; #endif // !SUPPORTS_REFLECTION // resolve constructor for the type var constructor = ResolveConstructor(context, availableConstructors, implementationType); #if DEBUG // trace output context.TraceBuilder.AppendConstructorResolve(implementationType, constructor); #endif // DEBUG // get constructor parameters and create array holding the parameters for the constructor var constructorParameters = constructor.GetParameters(); var invocationParameters = new object[constructorParameters.Length]; // resolve services for the constructor for (var index = 0; index < constructorParameters.Length; index++) { // the type of the service being resolved var serviceType = constructorParameters[index].ParameterType; // resolve service and add to constructor parameter invocation list invocationParameters[index] = context.Resolver.Resolve(serviceType, context); } // invoke constructor and constructor type return(constructor.Invoke(invocationParameters)); }
/// <summary> /// Tries to resolve an object from the manager. /// </summary> /// <param name="resolveContext">the current resolver context</param> /// <param name="scopeKey"> /// the <paramref name="scopeKey"/> the instance was created for; if /// <see langword="null"/> then the scope is global. /// </param> /// <returns>the resolved service; or default if the service could not be resolved</returns> public object Resolve(ServiceResolveContext resolveContext, object scopeKey = null) { // create the key for resolving the type from the scope var key = new KeyValuePair <Type, object>(resolveContext.ServiceType, scopeKey); return(_services.TryGetValue(key, out var service) ? service : default);
/// <summary> /// Initializes a new instance of the <see cref="ResolverException"/> class. /// </summary> /// <param name="message">the message</param> /// <param name="context">the current resolver context</param> public ResolverException(string message, ServiceResolveContext context) : this(BuildMessage(message, context)) => Context = context;
public object Create(ServiceResolveContext context) => throw new NotImplementedException();
protected override object CreateService(ServiceResolveContext context) => Reflector.Resolve <TImplementation>(context);
/// <summary> /// Creates the instance. /// </summary> /// <param name="context">the current resolver context</param> /// <returns>the instance</returns> #if NO_REFLECTION protected override object CreateService(ServiceResolveContext context) => Activator.CreateInstance <TImplementation>();
/// <summary> /// Tries to resolve an object from the manager. /// </summary> /// <param name="resolveContext">the current resolver context</param> /// <param name="scopeKey"> /// the <paramref name="scopeKey"/> the instance was created for; if /// <see langword="null"/> then the scope is global. /// </param> /// <returns>the resolved service; or default if the service could not be resolved</returns> public object Resolve(ServiceResolveContext resolveContext, object scopeKey = null) { // The transient lifetime always re-creates services. return(null); }
public static TImplementation Resolve <TImplementation>(ServiceResolveContext context) => (TImplementation)Resolve(typeof(TImplementation), context);
/// <summary> /// Resolves the matching constructor for the specified /// <paramref name="implementationType"/> with respecting the specified <paramref name="constructionMode"/>. /// </summary> /// <param name="context">the current resolver context</param> /// <param name="availableConstructors"> /// an enumerable that enumerates through the available constructors for the specified <paramref name="implementationType"/>. /// </param> /// <param name="implementationType"> /// the type of the service implementation to resolve the constructor for /// </param> /// <param name="constructionMode">the service construction mode.</param> /// <returns>the constructor chosen fro the specified <paramref name="implementationType"/></returns> /// <exception cref="ArgumentOutOfRangeException"> /// thrown if the specified <paramref name="constructionMode"/> is unsupported or not /// defined in the <see cref="ServiceConstructionMode"/> enumeration. /// </exception> /// <exception cref="ResolverException"> /// thrown if no passable constructor was found for the specified <paramref name="implementationType"/> /// </exception> public static ConstructorInfo ResolveConstructor(ServiceResolveContext context, IEnumerable <ConstructorInfo> availableConstructors, Type implementationType, ServiceConstructionMode constructionMode = ServiceConstructionMode.Mixed) { // check if no constructors are available if (!availableConstructors.Any()) { return(null); } // check whether the mode is mixed if (context.ConstructionMode == ServiceConstructionMode.Mixed) { // iterate through all constructors foreach (var constructor in availableConstructors) { // check if the constructor is preferred #if NET35 if (constructor.GetCustomAttributes(true).OfType <PreferConstructorAttribute>().Any()) #else // NET35 if (constructor.GetCustomAttribute <PreferConstructorAttribute>() != null) #endif // !NET35 { // constructor has the attribute return(constructor); } } } // search complexest constructor if (context.ConstructionMode == ServiceConstructionMode.PreferComplexConstructor || context.ConstructionMode == ServiceConstructionMode.Mixed) { // iterate through all available constructors and find the complexest var constructor = availableConstructors #if SUPPORTS_READONLY_COLLECTIONS .Select(s => new KeyValuePair <ConstructorInfo, IReadOnlyList <ParameterInfo> >(s, s.GetParameters())) .OrderByDescending(s => s.Value.Count) // order by parameter count (descending) #else // SUPPORTS_READONLY_COLLECTIONS .Select(s => new KeyValuePair <ConstructorInfo, ParameterInfo[]>(s, s.GetParameters())) .OrderByDescending(s => s.Value.Length) // order by parameter count (descending) #endif // !SUPPORTS_READONLY_COLLECTIONS .FirstOrDefault(s => CanUseConstructor(context.Register, s.Value)); // check if no constructor was found if (constructor.Key is null) { // throw exception: No constructor was found for the type. throw new ResolverException($"Could not find a passable constructor for '{implementationType}'.", context); } return(constructor.Key); } // search parameter-less constructor if (context.ConstructionMode == ServiceConstructionMode.PreferParameterlessConstructor) { // iterate through all available constructors and find a parameter-less var constructor = availableConstructors.FirstOrDefault(s => s.GetParameters().Length == 0); // check if no constructor was found if (constructor is null) { // throw exception: No parameter-less constructor throw new ResolverException($"Could not find a parameter-less constructor for '{implementationType}'.", context); } return(constructor); } // throw exception: Service Construction mode out of range throw new ArgumentOutOfRangeException(nameof(constructionMode), constructionMode, $"Invalid or unsupported service construction mode: '{constructionMode}'."); }
/// <summary> /// Creates the instance. /// </summary> /// <param name="context">the current resolver context</param> /// <returns>the instance</returns> protected override object CreateService(ServiceResolveContext context) => new TImplementation();