/// <summary> /// Called to apply this configuration to the passed <paramref name="targets"/> target container. /// </summary> /// <param name="targets"></param> public override void Configure(IRootTargetContainer targets) { if (targets == null) { throw new ArgumentNullException(nameof(targets)); } if (!targets.GetOption(EnableAutoFuncInjection.Default)) { return; } bool enableEnumerables = targets.GetOption(EnableEnumerableInjection.Default); targets.TargetRegistered += (object sender, Events.TargetRegisteredEventArgs e) => { if (e.Target is AutoFactoryTarget || (typeof(Delegate).IsAssignableFrom(e.Type) && e.Type.IsGenericType && ((e.Type.IsGenericTypeDefinition && FuncTypes.Contains(e.Type)) || FuncTypes.Contains(e.Type.GetGenericTypeDefinition())))) { return; } IRootTargetContainer root = (IRootTargetContainer)sender; var funcType = typeof(Func <>).MakeGenericType(e.Type); var existing = root.Fetch(funcType); if (existing == null || existing.UseFallback) { // you'd think we would bind to the target that was registered, but we don't because // that would prevent auto IEnumerable<delegate_type> from working, and would also prevent // decorators from working. root.Register(new AutoFactoryTarget(funcType, e.Type, Type.EmptyTypes)); } if (enableEnumerables) { var enumerableType = typeof(IEnumerable <>).MakeGenericType(e.Type); funcType = typeof(Func <>).MakeGenericType(enumerableType); existing = root.Fetch(funcType); if (existing == null || existing.UseFallback) { root.Register(new AutoFactoryTarget(funcType, enumerableType, Type.EmptyTypes)); } } }; }
/// <summary> /// Adds registrations for <see cref="Collection{T}"/> and <see cref="ReadOnlyCollection{T}"/> to the <paramref name="targets"/> (including /// their primary interfaces) so long as none of the types are already registered. /// </summary> /// <param name="targets"></param> public override void Configure(IRootTargetContainer targets) { if (targets == null) { throw new ArgumentNullException(nameof(targets)); } if (!targets.GetOption(Options.EnableCollectionInjection.Default)) { return; } if (targets.Fetch(typeof(Collection <>)) != null || targets.Fetch(typeof(ICollection <>)) != null || targets.Fetch(typeof(ReadOnlyCollection <>)) != null || targets.Fetch(typeof(IReadOnlyCollection <>)) != null) { return; } var collectionTarget = Target.ForConstructor(_collectionCtor); targets.Register(collectionTarget); targets.Register(collectionTarget, typeof(ICollection <>)); // there's only one constructor for ReadOnlyCollection anyway, so no need to disambiguate var roCollectionTarget = Target.ForType(typeof(ReadOnlyCollection <>)); targets.Register(roCollectionTarget); targets.Register(roCollectionTarget, typeof(IReadOnlyCollection <>)); }
/// <summary> /// Gets the compile context for the specified target under test. /// /// The <see cref="ICompileContext.TargetType"/> is automatically set to the <see cref="ITarget.DeclaredType"/> /// of the passed target. /// </summary> /// <param name="target">The target.</param> /// <param name="container">The container to use for the <see cref="ResolveContext"/> from which the compile context /// will be created. If null, then the <see cref="GetDefaultContainer"/> method is called.</param> /// <param name="targets">The target container to use for the compile context. If null, then the <paramref name="container"/> /// will be passed to the <see cref="GetDefaultTargetContainer(Container)"/> method (including if one is automatically /// built) - with the target container that's returned being used instead.</param> protected virtual ICompileContext GetCompileContext(ITarget target, Container container = null, IRootTargetContainer targets = null, Type targetType = null) { targets = targets ?? GetDefaultTargetContainer(container); container = container ?? GetDefaultContainer(targets); // to create a context we resolve the ITargetCompiler from the container. // this is usually an internal operation within the container itself. return(targets.GetOption <ITargetCompiler>() .CreateContext(new ResolveContext(container, targetType ?? target.DeclaredType), targets)); }
public EnumerableTargetContainer(IRootTargetContainer root) : base(root, typeof(IEnumerable <>)) { this._tracker = root.GetOption <TargetOrderTracker>(); if (this._tracker == null) { // this is the first enumerable container in the root // so create the tracker and register our own event handler // for adding enumerable types. root.SetOption(this._tracker = new TargetOrderTracker(Root)); Root.TargetRegistered += Root_TargetRegistered; } }
/// <summary> /// Adds the necessary registration to the passed root target container /// for <see cref="Lazy{T}"/> so long as no <see cref="ITargetContainer"/> is already /// registered. /// </summary> /// <param name="targets">The root target container to which this configuation will be applied.</param> public override void Configure(IRootTargetContainer targets) { if (targets == null) { throw new ArgumentNullException(nameof(targets)); } if (!targets.GetOption <EnableAutoLazyInjection>()) { return; } if (targets.FetchContainer(typeof(Lazy <>)) == null) { targets.RegisterContainer(typeof(Lazy <>), new AutoLazyTargetContainer(targets)); } }
/// <summary> /// Implementation of <see cref="OptionDependentConfigBase.Configure(IRootTargetContainer)"/> /// </summary> /// <param name="targets"></param> /// <remarks> /// This implementation registers a special target container (via <see cref="ITargetContainer.RegisterContainer(Type, ITargetContainer)"/>) /// for <see cref="IEnumerable{T}"/> in passed <paramref name="targets"/> /// if the <see cref="Options.EnableEnumerableInjection"/> option evaluates to <c>true</c> when read from <paramref name="targets"/>. /// /// This is the default value for that option anyway, so, as the remarks section on the class states, all that's required to enable /// the enumerable resolving behaviour is simply to make sure this configuration object is applied to an <see cref="IRootTargetContainer"/></remarks> public override void Configure(IRootTargetContainer targets) { if (targets == null) { throw new ArgumentNullException(nameof(targets)); } // if an option has already been set on the target container which disables automatic enumerables, // then do not apply the configuration. if (!targets.GetOption(Options.EnableEnumerableInjection.Default)) { return; } if (targets.FetchContainer(typeof(IEnumerable <>)) == null) { targets.RegisterContainer(typeof(IEnumerable <>), new EnumerableTargetContainer(targets)); } }
/// <summary> /// Implements the <see cref="OptionDependentConfigBase.Configure(IRootTargetContainer)"/> abstract method /// by configuring the passed <paramref name="targets"/> so it can produce targets for any array type, regardless /// of whether a single object has been registered for the array's element type. /// /// After enabling, the ability to register specific targets for concrete array types will still be present. /// </summary> /// <param name="targets"></param> public override void Configure(IRootTargetContainer targets) { if (targets == null) { throw new ArgumentNullException(nameof(targets)); } // REVIEW: should this also check that EnableEnumerableInjection is true? // At the moment, it's just dependent upon the Enumerable config; but it actually needs it to // be *enabled* too. if (!targets.GetOption(Options.EnableArrayInjection.Default)) { return; } targets.RegisterContainer(typeof(Array), new ArrayTargetContainer(targets)); targets.SetOption <ITargetContainerTypeResolver, Array>(ArrayTypeResolver.Instance); }
/// <summary> /// Configures the passed <paramref name="targets"/> to enable auto injection of <see cref="List{T}"/>, <see cref="IList{T}"/> /// and <see cref="IReadOnlyList{T}"/> by registering a <see cref="Targets.GenericConstructorTarget"/> for /// <see cref="List{T}"/> for all three types - so long as none of them already have a registration. /// </summary> /// <param name="targets"></param> public override void Configure(IRootTargetContainer targets) { if (targets == null) { throw new ArgumentNullException(nameof(targets)); } if (!targets.GetOption(Options.EnableListInjection.Default)) { return; } if (targets.Fetch(typeof(List <>)) != null || targets.Fetch(typeof(IList <>)) != null || targets.Fetch(typeof(IReadOnlyList <>)) != null) { return; } var target = Target.ForConstructor(_listCtor); targets.Register(target); targets.Register(target, typeof(IList <>)); // might be an argument here for a dedication implementation to prevent casting->modification targets.Register(target, typeof(IReadOnlyList <>)); }