/// <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); }
/// <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); }
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<Bar></c> /// is more specific than <c>IFoo<></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); }
/// <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> 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. }
/// <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)); }
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); }
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)); }