/// <summary>
        /// Sets the passed <paramref name="option"/> into the <paramref name="targets"/> target container, associating
        /// it with the given <paramref name="serviceType"/>.
        ///
        /// The value can later be retrieved through a call to <see cref="GetOption{TOption, TService}(ITargetContainer, TOption)"/>
        /// or <see cref="GetOption{TOption}(ITargetContainer, Type, TOption)"/>, passing the same type, or a derived type.
        /// </summary>
        /// <typeparam name="TOption">The type of option to be set.</typeparam>
        /// <param name="targets">The target container into which the option will be set.</param>
        /// <param name="option">The option value to be set</param>
        /// <param name="serviceType">The type against which the option is to be set.  It's called 'serviceType' because the majority
        /// of the time, you will used this method and its generic overload to customise behaviour for specific types.  If <c>null</c>,
        /// then it's equivalent to calling <see cref="SetOption{TOption}(ITargetContainer, TOption)"/>.</param>
        /// <returns>The target container on which the method is called, to enable method chaining.</returns>
        public static ITargetContainer SetOption <TOption>(this ITargetContainer targets, TOption option, Type serviceType)
            where TOption : class
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            if (option == null)
            {
                throw new ArgumentNullException(nameof(option));
            }

            if (serviceType == null)
            {
                return(SetOption <TOption>(targets, option));
            }

            // this is cheeky - we create an instance of OptionContainer<TOption> to service
            // the type OptionContainer<TService, TOption>.  When we retrieve it in the various GetOption
            // methods, we *expect* only an OptionContainer<TOption> despite the fact that we fetch
            // a target for the <TService, TOption> pair.  That's part of the reason why all this stuff is
            // internal.
            targets.Register(new OptionContainer <TOption>(option),
                             typeof(IOptionContainer <,>).MakeGenericType(serviceType, typeof(TOption)));

            return(targets);
        }
Example #2
0
        /// <summary>
        /// Called to register multiple targets against the same type.
        ///
        /// It is the same as calling <see cref="ITargetContainer.Register(ITarget, Type)"/> multiple times
        /// with the different targets.
        /// </summary>
        /// <param name="targetContainer">The container on which the registration is to be performed.</param>
        /// <param name="targets">The targets to be registered - all must support a common service type (potentially
        /// passed in the <paramref name="commonServiceType"/> argument.</param>
        /// <param name="commonServiceType">Optional - if provided, then this will be used as the common service type
        /// for registration.  If not provided, then the <see cref="ITarget.DeclaredType"/> of the first target
        /// will be used.</param>
        /// <remarks>If the container has the capability to create enumerables automatically (enabled by the
        /// <see cref="Configuration.InjectEnumerables"/> target container behaviour - which is switched on by default)
        /// then each target will be returned when an IEnumerable of the common service type is requested.</remarks>
        public static void RegisterMultiple(this ITargetContainer targetContainer, IEnumerable <ITarget> targets, Type commonServiceType = null)
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }
            var targetArray = targets.ToArray();

            if (targets.Any(t => t == null))
            {
                throw new ArgumentException("All targets must be non-null", "targets");
            }

            // for now I'm going to take the common type from the first target.
            if (commonServiceType == null)
            {
                commonServiceType = targetArray[0].DeclaredType;
            }

            if (targetArray.All(t => t.SupportsType(commonServiceType)))
            {
                foreach (var target in targets)
                {
                    targetContainer.Register(target, commonServiceType);
                }
            }
            else
            {
                throw new ArgumentException(string.Format(ExceptionResources.TargetDoesntSupportType_Format, commonServiceType), "target");
            }
        }
        /// <summary>
        /// Register a type by constructor (represented by the expression <paramref name="newExpr"/>).
        /// </summary>
        /// <typeparam name="TObject"></typeparam>
        /// <param name="targets"></param>
        /// <param name="newExpr">A lambda expression whose <see cref="LambdaExpression.Body"/> is a <see cref="NewExpression"/>
        /// which identifies the constructor that is to be used to create the instance of <typeparamref name="TObject"/>.  An exception
        /// will be thrown if the lambda does not follow this pattern.</param>
        /// <param name="configureMemberBinding">A callback which configures a custom member binding via the
        /// <see cref="IMemberBindingBehaviourBuilder{TInstance}"/> interface.  A new builder will be created and passed to this
        /// callback.</param>
        /// <remarks>Note that you can achieve a similar result by simply registering an expression which
        /// represents a call to a type's constructor.
        ///
        /// **Generic constructors**
        /// If you wish to register an open generic type by constructor through the use of an expression, then you
        /// need to use the <see cref="RegisterGenericConstructor{TObject}(ITargetContainer, Expression{Func{TObject}}, IMemberBindingBehaviour)"/>
        /// overload.</remarks>
        public static void RegisterConstructor <TObject>(
            this ITargetContainer targets,
            Expression <Func <TObject> > newExpr,
            Action <IMemberBindingBehaviourBuilder <TObject> > configureMemberBinding)
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            if (configureMemberBinding == null)
            {
                throw new ArgumentNullException(nameof(configureMemberBinding));
            }

            var ctor = Extract.Constructor(newExpr ?? throw new ArgumentNullException(nameof(newExpr)));

            if (ctor == null)
            {
                throw new ArgumentException($"The expression ${newExpr} does not represent a NewExpression", nameof(newExpr));
            }

            var behaviour = MemberBindingBehaviour.For <TObject>();

            configureMemberBinding(behaviour);
            targets.Register(Target.ForConstructor(ctor, behaviour.BuildBehaviour()));
        }
        /// <summary>
        /// Registers the expression in the target container
        /// </summary>
        /// <param name="targetContainer">The target container in which the registration will be made.</param>
        /// <param name="expression">The expression to be registered.</param>
        /// <param name="declaredType">Optional.  The <see cref="ITarget.DeclaredType"/> of the target to be created,
        /// if different from the <see cref="Expression.Type"/> of the <paramref name="expression"/> (or its
        /// <see cref="LambdaExpression.Body"/> if the expression is a <see cref="LambdaExpression"/>).
        ///
        /// Will also override the type against which the expression will be registered if provided.</param>
        /// <param name="scopeBehaviour">Optional.  Controls how the object generated from the compiled expression will be
        /// tracked if the target is executed within an <see cref="ContainerScope" />.  The default is <see cref="ScopeBehaviour.Implicit" />.</param>
        /// <param name="scopePreference">Optional.  If <paramref name="scopeBehaviour"/> is not <see cref="ScopeBehaviour.None"/>, then this controls the
        /// type of scope in which the instance should be tracked.  Defaults to <see cref="ScopePreference.Current"/>.  <see cref="ScopePreference.Root"/>
        /// should be used if the result of the delegate is effectively a singleton.</param>
        public static void RegisterExpression(
            this ITargetContainer targetContainer,
            Expression expression,
            Type declaredType               = null,
            ScopeBehaviour scopeBehaviour   = ScopeBehaviour.Implicit,
            ScopePreference scopePreference = ScopePreference.Current)
        {
            if (targetContainer == null)
            {
                throw new ArgumentNullException(nameof(targetContainer));
            }

            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            ITarget toRegister = new ExpressionTarget(expression, declaredType);

            if (scopeBehaviour == ScopeBehaviour.Explicit)
            {
                toRegister = toRegister.Scoped();
            }
            else if (scopeBehaviour == ScopeBehaviour.None)
            {
                toRegister = toRegister.Unscoped();
            }

            targetContainer.Register(toRegister);
        }
Example #5
0
 internal static IEnumerable <TObj> FetchAllDirect <TObj>(this ITargetContainer targets)
 {
     return(targets.FetchAll(typeof(TObj))
            .Select(t => FetchDirect(t, targets, typeof(TObj)))
            .Where(r => r != null)
            .OfType <TObj>());
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="OverridingTargetContainer"/> class.
        /// </summary>
        /// <param name="parent">Required. The parent target container.</param>
        /// <param name="config">Optional.  The configuration to apply to this target container.  If null, then
        /// the <see cref="TargetContainer.DefaultConfig"/> is used.
        /// </param>
        public OverridingTargetContainer(ITargetContainer parent, ITargetContainerConfig config = null)
            : base()
        {
            Parent = parent ?? throw new ArgumentNullException(nameof(parent));

            (config ?? DefaultConfig).Configure(this);
        }
        /// <summary>
        /// Constructs a <see cref="DelegateTarget"/> from the passed factory delegate (optionally with the given <paramref name="declaredType"/>,
        /// <paramref name="scopeBehaviour"/> and <paramref name="scopePreference"/>) and registers it in the target container.
        /// </summary>
        /// <param name="targetContainer">The target container in which the new target is to registered</param>
        /// <param name="factory">The factory delegate that is to be executed by the <see cref="DelegateTarget"/> that is created.</param>
        /// <param name="declaredType">Optional - if provided, then it overrides the <see cref="ITarget.DeclaredType"/> of the <see cref="DelegateTarget"/>
        /// that is created which, in turn, will change the type against which the target will be registered in the target container.  If null, then
        /// the return type of the factory will be used.</param>
        /// <param name="scopeBehaviour">Optional.  Controls how the object generated from the factory delegate will be
        /// tracked if the target is executed within an <see cref="ContainerScope" />.  The default is <see cref="ScopeBehaviour.None" /> - which means
        /// no disposal will take place.  Be careful with changing this - if the delegate produces new instances each time it's used, then
        /// <see cref="ScopeBehaviour.Implicit"/> is suitable; if not, then only <see cref="ScopeBehaviour.None"/> or <see cref="ScopeBehaviour.Explicit"/>
        /// are suitable.</param>
        /// <param name="scopePreference">Optional.  If <paramref name="scopeBehaviour"/> is not <see cref="ScopeBehaviour.None"/>, then this controls the
        /// type of scope in which the instance should be tracked.  Defaults to <see cref="ScopePreference.Current"/>.  <see cref="ScopePreference.Root"/>
        /// should be used if the result of the delegate is effectively a singleton.</param>
        public static void RegisterDelegate(
            this ITargetContainer targetContainer,
            Delegate factory,
            Type declaredType               = null,
            ScopeBehaviour scopeBehaviour   = ScopeBehaviour.Implicit,
            ScopePreference scopePreference = ScopePreference.Current)
        {
            if (targetContainer == null)
            {
                throw new ArgumentNullException(nameof(targetContainer));
            }
            if (factory == null)
            {
                throw new ArgumentNullException(nameof(factory));
            }

            ITarget toRegister = null;

            if (factory.GetMethodInfo().GetParameters()?.Length > 0)
            {
                toRegister = new DelegateTarget(factory, declaredType, scopeBehaviour: scopeBehaviour, scopePreference: scopePreference);
            }
            else
            {
                toRegister = new NullaryDelegateTarget(factory, declaredType, scopeBehaviour: scopeBehaviour, scopePreference: scopePreference);
            }

            targetContainer.Register(toRegister);
        }
        /// <summary>
        /// Gets an option either specific to the <paramref name="serviceType"/>, or a global option (if <see cref="Options.EnableGlobalOptions"/> is
        /// enabled), of the type <typeparamref name="TOption"/>
        /// from the <paramref name="targets"/> target container, returning the <paramref name="default"/> if the option has not been explicitly set.
        /// </summary>
        /// <typeparam name="TOption">The type of option to retrieve</typeparam>
        /// <param name="targets">Required. The target container from which the option is to be read.</param>
        /// <param name="serviceType">A type for which the option is to be retrieved.  Note that the default behaviour is to search for
        /// an option which is specific to this service, and then to search for more generally-defined options.  See the remarks section for more.</param>
        /// <param name="default">The default value to return if the option has not been set.</param>
        /// <returns>An option value which was either previously set, or the <paramref name="default"/> if not</returns>
        /// <remarks>Options are frequently used to control how a Rezolver container interprets registrations.  Take, for example, the
        /// <see cref="Options.AllowMultiple"/> option - which is used to control whether a target container accepts multiple registrations
        /// for a given type.
        ///
        /// When defined globally (i.e. without a service type) it determines whether multiple registrations can be performed for all types.  However,
        /// it can also be defined on a per-service basis - so, for example, if you want to restrict an application only to register one target for a
        /// particular service - e.g. <c>IMyApplication</c> - then you can set the <see cref="AllowMultiple"/> option to <c>false</c> specifically against
        /// that type, and multiple registrations will result in a runtime error.
        ///
        /// When searching for service-specific options, generics are automatically processed in descending order of specificity - i.e. <c>IFoo&lt;Bar&gt;</c>
        /// is more specific than <c>IFoo&lt;&gt;</c> - so you can set options for a specific closed generic, or its open generic.
        ///
        /// **Global Fallback**
        ///
        /// In the absence of a service-specific option, a globally-defined option will instead be used if the <see cref="EnableGlobalOptions"/> option
        /// is set to <c>true</c> for the <paramref name="targets"/> target container.  By default, this is enabled.</remarks>
        public static TOption GetOption <TOption>(this ITargetContainer targets, Type serviceType, TOption @default = default)
            where TOption : class
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException(nameof(serviceType));
            }

            bool useGlobalFallback = GetOption(targets, EnableGlobalOptions.Default);

            var optionContainer = (IOptionContainer <TOption>)targets.FetchDirect(typeof(IOptionContainer <,>)
                                                                                  .MakeGenericType(serviceType, typeof(TOption)));

            // currently internal-only option container which allows us to set options
            // that take effect only for generic types (closed/open classes, structs or interfaces)
            if (optionContainer == null && serviceType.IsGenericType)
            {
                optionContainer = targets.FetchDirect <IAnyGenericOptionContainer <TOption> >();
            }

            if (optionContainer == null && useGlobalFallback)
            {
                optionContainer = targets.FetchDirect <IOptionContainer <TOption> >();
            }

            return(optionContainer?.Option ?? @default);
        }
 internal static void RaiseEvent <TEvent>(this ITargetContainer container, TEvent e)
 {
     foreach (var handler in GetEventHandlers(container, e))
     {
         handler.Handle(container, e);
     }
 }
        /// <summary>
        /// Get all options of the type <typeparamref name="TOption"/> which have been set for the service type <paramref name="serviceType"/>
        /// or any of its derivatives.  Globally-defined options will also be included in the results unless the <see cref="EnableGlobalOptions"/>
        /// option has been set to <c>false</c> on the <paramref name="targets"/> target container.
        /// </summary>
        /// <typeparam name="TOption">The type of option to be retrieved</typeparam>
        /// <param name="targets">Required.  The target container from which the options are to be read.</param>
        /// <param name="serviceType">Required.  The service type for which options are to be retrieved.</param>
        /// <returns>An enumerable of the type <typeparamref name="TOption"/> containing zero or more options that have been
        /// set.</returns>
        public static IEnumerable <TOption> GetOptions <TOption>(this ITargetContainer targets, Type serviceType)
            where TOption : class
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            if (serviceType == null)
            {
                throw new ArgumentNullException(nameof(serviceType));
            }

            // global fallback in this instance causes all options - service-specific or not - to be included
            // in the enumerable.
            bool useGlobalFallback = GetOption(targets, EnableGlobalOptions.Default);

            var optionContainers = targets.FetchAllDirect(typeof(IOptionContainer <,>)
                                                          .MakeGenericType(serviceType, typeof(TOption))).Cast <IOptionContainer <TOption> >();

            if (useGlobalFallback)
            {
                optionContainers = optionContainers.Concat(targets.FetchAllDirect <IOptionContainer <TOption> >());
            }

            return(optionContainers.Select(o => o.Option));
        }
        /// <summary>
        /// Registers an alias for one type to another type.
        ///
        /// The created entry will effectively represent a second Resolve call into the container for the aliased type.
        /// </summary>
        /// <param name="targetContainer">The builder in which the alias is to be registered</param>
        /// <param name="aliasType">The type to be registered as an alias</param>
        /// <param name="originalType">The type being aliased.</param>
        /// <remarks>Use this when it's important that a given target type is always served through the same compiled target, even when the consumer
        /// expects it to be of a different type.  A very common scenario is when you have a singleton instance of the <paramref name="originalType" />,
        /// and need to serve that same instance for <paramref name="aliasType"/>.  If you register the same singleton for both types, you get two
        /// separate singletons for each type, whereas if you create an alias, both will be served by the same alias.
        /// </remarks>
        public static void RegisterAlias(this ITargetContainer targetContainer, Type aliasType, Type originalType)
        {
            if (targetContainer == null)
            {
                throw new ArgumentNullException(nameof(targetContainer));
            }
            if (aliasType == originalType)
            {
                throw new ArgumentException("The aliased type and its alias must be different", nameof(aliasType));
            }

            ITarget target = new ResolvedTarget(originalType);

            // if there's no implicit conversion to our alias type from the aliased type, but there is
            // the other way around, then we need to stick in an explicit change of type, otherwise the registration will
            // fail.  This does, unfortunately, give rise to the situation where we could be performing an invalid cast - but that
            // will come out in the wash at runtime.
            if (!aliasType.IsAssignableFrom(originalType) &&
                originalType.IsAssignableFrom(aliasType))
            {
                target = new ChangeTypeTarget(target, aliasType);
            }

            targetContainer.Register(target, aliasType);
        }
        /// <summary>
        /// Strongly-typed version of <see cref="CompileTarget(ITargetCompiler, ITarget, ResolveContext, ITargetContainer)"/> when the
        /// <typeparamref name="TService"/> is known at compile-time.
        /// </summary>
        /// <typeparam name="TService">The type of object to be returned by the factory.S</typeparam>
        /// <param name="compiler">Required.  The compiler.</param>
        /// <param name="target">Required.  The target to be compiled.</param>
        /// <param name="resolveContext">Required.  The current <see cref="ResolveContext"/></param>
        /// <param name="targets">Required.  Used to locate dependencies during compilation.</param>
        /// <returns>A strongly-typed delegate representing the passed <paramref name="target"/>.
        /// Invoking this delegate should produce an instance of the type <typeparamref name="TService"/>.</returns>
        public static Func <ResolveContext, TService> CompileTarget <TService>(this ITargetCompiler compiler,
                                                                               ITarget target,
                                                                               ResolveContext resolveContext,
                                                                               ITargetContainer targets)
        {
            if (compiler == null)
            {
                throw new ArgumentNullException(nameof(compiler));
            }

            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            if (resolveContext == default)
            {
                throw new ArgumentNullException(nameof(resolveContext));
            }

            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            return(compiler.CompileTarget <TService>(target, compiler.CreateContext(resolveContext, targets)));
        }
        /// <summary>
        /// Same as the <see cref="RegisterType{TObject}(ITargetContainer, Action{IMemberBindingBehaviourBuilder{TObject}})"/> method, except this
        /// creates a registration for <typeparamref name="TService"/> that will be implemented by instances of the type <typeparamref name="TObject"/>,
        /// created via constructor injection.
        /// </summary>
        /// <typeparam name="TObject"></typeparam>
        /// <typeparam name="TService"></typeparam>
        /// <param name="targets">The target container on which the registration is to be performed.</param>
        /// <param name="configureMemberBinding">A callback that will be invoked with a new <see cref="IMemberBindingBehaviourBuilder{TInstance}"/>
        /// object that you can use to configure a custom member binding behaviour for the type <typeparamref name="TObject"/>.  The
        /// <see cref="IMemberBindingBehaviourBuilder{TInstance}.BuildBehaviour"/> method will be called after executing your callback to
        /// obtain the final <see cref="IMemberBindingBehaviour"/>.</param>
        public static void RegisterType <TObject, TService>(this ITargetContainer targets, Action <IMemberBindingBehaviourBuilder <TObject> > configureMemberBinding)
            where TObject : TService
        {
            var factory = MemberBindingBehaviour.For <TObject>();

            configureMemberBinding?.Invoke(factory);
            targets.RegisterType <TObject, TService>(factory.BuildBehaviour());
        }
 /// <summary>
 /// Overrides the base method to record that a target container has been registered.
 /// </summary>
 /// <param name="container">The target container that was registered</param>
 /// <param name="type">The type against which the target container was registered.</param>
 protected override void OnTargetContainerRegistered(ITargetContainer container, Type type)
 {
     if (!_hasRegistrations)
     {
         _hasRegistrations = true;
     }
     base.OnTargetContainerRegistered(container, type);
 }
        public void ShouldGetEnumerableTargetWhenNoRegistrations()
        {
            ITargetContainer targets = CreateTargets();

            var result = Assert.IsType <EnumerableTarget>(targets.Fetch(typeof(IEnumerable <int>)));

            Assert.True(result.UseFallback);
        }
Example #16
0
 /// <summary>
 /// Registers an instance to be used when resolve a particular service type via the <see cref="ObjectTarget"/>
 /// </summary>
 /// <param name="targetContainer">The target container which will receive the registration.</param>
 /// <param name="obj">Required, but can be <c>null</c>.  The instance that will be resolved when the service type is requested.</param>
 /// <param name="declaredType">Type to be set as the <see cref="ITarget.DeclaredType"/> of the <see cref="ObjectTarget"/>
 /// that is created for <paramref name="obj"/>, if different from the object's type.</param>
 /// <param name="serviceType">The service type against which this object is to be registered, if different
 /// from <paramref name="declaredType"/> (or the object's type).</param>
 /// <param name="scopeBehaviour">Sets the <see cref="ITarget.ScopeBehaviour"/> for the <see cref="ObjectTarget"/> that's created</param>
 /// <remarks><c>null</c> objects are implicitly treated as <see cref="System.Object"/> if <paramref name="declaredType"/> is not passed.</remarks>
 public static void RegisterObject(this ITargetContainer targetContainer, object obj, Type declaredType = null, Type serviceType = null, ScopeBehaviour scopeBehaviour = ScopeBehaviour.None)
 {
     if (targetContainer == null)
     {
         throw new ArgumentNullException(nameof(targetContainer));
     }
     targetContainer.Register(Target.ForObject(obj, declaredType ?? obj?.GetType(), scopeBehaviour: scopeBehaviour), serviceType ?? declaredType ?? obj?.GetType());
 }
        public override ITargetContainer CombineWith(ITargetContainer existing, Type type)
        {
            if (existing is EnumerableTargetContainer)
            {
                return(existing);
            }

            return(base.CombineWith(existing, type));
        }
Example #18
0
        // <example>
        public void ConfigureContainer(ITargetContainer container)
        {
            //by declaring this method - even if empty - you trigger the
            //creation of the ITargetContainer which will ultimately
            //be used to create the IContainer that will be used
            //as the application's container.

            //Here you can perform additional registrations/configuration on the
            //ITargetContainer here.
        }
Example #19
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ExpressionCompileContext"/> class.
 /// </summary>
 /// <seealso cref="CompileContext.CompileContext(ResolveContext, ITargetContainer, Type)"/>.
 /// <param name="resolveContext">Required.  The container for which the compilation is being performed.  When compiling in response to
 /// a call to <see cref="Container.Resolve(ResolveContext)"/>, the container which first receives the call should be
 /// the one passed here.</param>
 /// <param name="dependencyTargetContainer">Required - target container used for dependency lookups.  As with the base class
 /// this is actually wrapped in a new <see cref="OverridingTargetContainer"/> and used as this class' implementation of
 /// <see cref="ITargetContainer"/>.</param>
 /// <param name="targetType">Optional. Will be set into the <see cref="CompileContext.TargetType" /> property.  If null, then any
 /// <see cref="ITarget"/> that is compiled should be compiled for its own <see cref="ITarget.DeclaredType"/>.</param>
 /// <param name="resolveContextExpression">Optional, mapped to <see cref="ResolveContextParameterExpression"/> - the default
 /// for this (i.e. when you leave it as null) is to use the static <see cref="DefaultResolveContextParameterExpression"/>
 /// and generally it should always be left as that.
 ///
 /// The <see cref="ExpressionCompiler"/>, when building expressions to turn into compiled lambdas, uses this as the main parameter
 /// on the lambda itself.</param>
 protected internal ExpressionCompileContext(ResolveContext resolveContext,
                                             ITargetContainer dependencyTargetContainer,
                                             Type targetType = null,
                                             ParameterExpression resolveContextExpression = null)
     : base(resolveContext, dependencyTargetContainer, targetType)
 {
     this._resolveContextExpression = resolveContextExpression ?? DefaultResolveContextParameterExpression;
     this._sharedExpressions        = new Dictionary <SharedExpressionKey, Expression>(20);
     RegisterExpressionTargets();
 }
        /// <summary>
        /// Generic version of the <see cref="GetOptions{TOption}(ITargetContainer, Type)"/> method.  See the documentation on that method
        /// for more.
        /// </summary>
        /// <typeparam name="TOption">The type of option to be retrieved</typeparam>
        /// <typeparam name="TService">The service type for which options are to be retrieved.</typeparam>
        /// <param name="targets">Required.  The target container from which the options are to be read.</param>
        /// <returns>An enumerable of the type <typeparamref name="TOption"/> containing zero or more options that have been
        /// set.</returns>
        public static IEnumerable <TOption> GetOptions <TOption, TService>(this ITargetContainer targets)
            where TOption : class
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            return(GetOptions <TOption>(targets, typeof(TService)));
        }
        /// <summary>
        /// Gets all globally-defined options of the type <typeparamref name="TOption"/> from the <paramref name="targets"/> target container,
        /// returning an empty enumerable if none have been set.
        /// </summary>
        /// <typeparam name="TOption">The type of option to retrieve</typeparam>
        /// <param name="targets">Required. The target container from which the options are to be read.</param>
        /// <returns>An enumerable of the type <typeparamref name="TOption"/> containing zero or more options that have been
        /// set.</returns>
        public static IEnumerable <TOption> GetOptions <TOption>(this ITargetContainer targets)
            where TOption : class
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            return(targets.FetchAllDirect <IOptionContainer <TOption> >().Select(o => o.Option));
        }
        /// <summary>
        /// Implements <see cref="ITargetContainer.CombineWith(ITargetContainer, Type)"/> by wrapping the
        /// <paramref name="existing"/> container and returning itself.
        ///
        /// This allows decorators to be applied on top of decorators; and decorators to be added after types
        /// have begun to be registered in another target container.
        /// </summary>
        /// <param name="existing">The existing <see cref="ITargetContainer" /> instance that this instance is to be combined with</param>
        /// <param name="type">The type that the combined container owner will be registered under.</param>
        /// <exception cref="InvalidOperationException">If this target container is already decorating another container</exception>
        public ITargetContainer CombineWith(ITargetContainer existing, Type type)
        {
            if (Inner != null)
            {
                throw new InvalidOperationException("Already decorating another container");
            }

            Inner = existing;
            return(this);
        }
        /// <summary>
        /// Generic equivalent of <see cref="GetOption{TOption}(ITargetContainer, Type, TOption)"/>.  See documentation on that method for more.
        /// </summary>
        /// <typeparam name="TOption">The type of option to retrieve</typeparam>
        /// <typeparam name="TService">The service type for which the option is to be retrieved</typeparam>
        /// <param name="targets">That target container from which the option is to be read.</param>
        /// <param name="default">The default value to be returned if the option is not set.</param>
        /// <returns>An option value which was either previously set, or the <paramref name="default"/> if not</returns>
        public static TOption GetOption <TOption, TService>(this ITargetContainer targets, TOption @default = default)
            where TOption : class
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            return(GetOption(targets, typeof(TService), @default));
        }
Example #24
0
        internal static object FetchDirect(this ITargetContainer targets, Type objectType)
        {
            var result = targets.Fetch(objectType);

            if (result != null)
            {
                return(FetchDirect(result, targets, objectType));
            }

            return(result);
        }
        public void ShouldGetEnumerableTargetWithOneRegistration()
        {
            ITargetContainer targets = CreateTargets();

            targets.RegisterType <NoCtor>();

            var result = Assert.IsType <EnumerableTarget>(targets.Fetch(typeof(IEnumerable <NoCtor>)));

            Assert.False(result.UseFallback);
            Assert.Single(result.Targets);
        }
        public void ShouldGetEnumerableTargetAfterRegisterMultipleOfDifferentTypesWithCommonBase()
        {
            ITargetContainer targets = CreateTargets();

            targets.RegisterMultiple(new[] { Target.ForType <NoCtor>(), Target.ForType <DefaultCtor>() }, typeof(NoCtor));

            var result = Assert.IsType <EnumerableTarget>(targets.Fetch(typeof(IEnumerable <NoCtor>)));

            Assert.False(result.UseFallback);
            Assert.Equal(2, result.Targets.Count());
        }
        /// <summary>
        /// Gets a globally-defined option of the type <typeparamref name="TOption"/> from the <paramref name="targets"/> target container,
        /// returning the <paramref name="default"/> if the option has not been explicitly set.
        /// </summary>
        /// <typeparam name="TOption">The type of option to retrieve</typeparam>
        /// <param name="targets">Required. The target container from which the option is to be read.</param>
        /// <param name="default">The default value to return if the option has not been set.</param>
        /// <returns>An option value which was either previously set, or the <paramref name="default"/> if not</returns>
        public static TOption GetOption <TOption>(this ITargetContainer targets, TOption @default = default)
            where TOption : class
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            var optionContainer = targets.FetchDirect <IOptionContainer <TOption> >();

            return(optionContainer?.Option ?? @default);
        }
Example #28
0
 private static void RegisterComplexObject(ITargetContainer targets)
 {
     targets.RegisterSingleton <FirstService, IFirstService>();
     targets.RegisterSingleton <SecondService, ISecondService>();
     targets.RegisterSingleton <ThirdService, IThirdService>();
     targets.RegisterType <SubObjectOne, ISubObjectOne>();
     targets.RegisterType <SubObjectTwo, ISubObjectTwo>();
     targets.RegisterType <SubObjectThree, ISubObjectThree>();
     targets.RegisterType <Complex1, IComplex1>();
     targets.RegisterType <Complex2, IComplex2>();
     targets.RegisterType <Complex3, IComplex3>();
 }
        /// <summary>
        /// Registers a type by constructor alone.
        /// </summary>
        /// <param name="targets"></param>
        /// <param name="constructor">The constructor to be bound. The <see cref="MemberInfo.DeclaringType"/> will be used
        /// as the service type to be registered against.</param>
        /// <param name="memberBindingBehaviour">Optional. If you wish to bind members on the new instance, passing a member binding
        /// behaviour here.</param>
        /// <remarks>If the <paramref name="constructor"/> belongs to an open generic type, then a <see cref="Targets.GenericConstructorTarget"/>
        /// will be created and registered.</remarks>
        public static void RegisterConstructor(
            this ITargetContainer targets,
            ConstructorInfo constructor,
            IMemberBindingBehaviour memberBindingBehaviour = null)
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            targets.Register(Target.ForConstructor(constructor ?? throw new ArgumentNullException(nameof(constructor)), memberBindingBehaviour));
        }
        /// <summary>
        /// Creates and registers a target bound to the constructor of a generic type definition using the
        /// <see cref="Target.ForGenericConstructor{TExample}(Expression{Func{TExample}}, IMemberBindingBehaviour)"/> factory method.
        ///
        /// See the documentation on that method for more.
        ///
        /// The registration will be made against the open generic type.
        /// </summary>
        /// <typeparam name="TExample">Must be a generic type which represents a concrete generic whose generic type definition will be
        /// bound by the created target.  This type is also used as the service type for the registration.</typeparam>
        /// <param name="targets">The container into which the registration will be made.</param>
        /// <param name="newExpr">Exemplar expression which is used to identify the constructor to be bound.</param>
        /// <param name="memberBindingBehaviour">A member binding behaviour to be passed to the created target</param>
        /// <seealso cref="Target.ForGenericConstructor{TExample}(Expression{Func{TExample}}, IMemberBindingBehaviour)"/>
        public static void RegisterGenericConstructor <TExample>(
            this ITargetContainer targets,
            Expression <Func <TExample> > newExpr,
            IMemberBindingBehaviour memberBindingBehaviour = null)
        {
            if (targets == null)
            {
                throw new ArgumentNullException(nameof(targets));
            }

            targets.Register(Target.ForGenericConstructor(newExpr, memberBindingBehaviour));
        }