示例#1
0
        private IPlan[] CreatePlans(Type requestedType, INode current, string bindingName, string planName, INode planRoot, IConstructorArgument[] arguments)
        {
            var resolvedMappings = ResolveTypes(requestedType, bindingName, current);
            var plans            = (IPlan[])Activator.CreateInstance(typeof(IPlan <>).MakeGenericType(requestedType).MakeArrayType(), resolvedMappings.Length);

            for (var i = 0; i < resolvedMappings.Length; i++)
            {
                var resolvedMapping = resolvedMappings[i];

                // If the resolved target is a generic type definition, we need to fill in the
                // generic type arguments from the request.
                var targetNonGeneric = resolvedMapping.Target;
                if (targetNonGeneric != null && targetNonGeneric.IsGenericTypeDefinition)
                {
                    targetNonGeneric = targetNonGeneric.MakeGenericType(requestedType.GenericTypeArguments);
                }

                var scopeNode = current;
                if (resolvedMapping.LifetimeScope != null)
                {
                    scopeNode = resolvedMapping.LifetimeScope.GetContainingNode();
                }

                if (scopeNode != null && resolvedMapping.UniquePerScope)
                {
                    var existing =
                        scopeNode.Children.FirstOrDefault(x => x.Type != null && x.Type.IsAssignableFrom(targetNonGeneric));
                    if (existing != null)
                    {
                        if (existing.Planned && existing.PlanRoot != planRoot)
                        {
                            // Flag that the plan root is now dependant on the other
                            // plan being resolved.
                            planRoot?.DependentOnPlans.Add(existing.PlanRoot);
                        }

                        plans[i] = existing;
                        continue;
                    }
                }

                Type nodeToCreate;
                if (targetNonGeneric != null)
                {
                    nodeToCreate = typeof(DefaultNode <>).MakeGenericType(targetNonGeneric);
                }
                else
                {
                    nodeToCreate = typeof(DefaultNode <>).MakeGenericType(requestedType);
                }
                var createdNode = (DefaultNode)Activator.CreateInstance(nodeToCreate);
                createdNode.Name     = string.Empty;
                createdNode.Parent   = scopeNode;
                createdNode.Planned  = true;
                createdNode.Type     = targetNonGeneric ?? requestedType;
                createdNode.PlanName = planName;
                createdNode.PlanRoot = planRoot;

                if (createdNode.Type.ContainsGenericParameters)
                {
                    throw new InvalidOperationException("The type still contained generic type parameters even after initial binding resolution.");
                }

                // If there is no plan root, then we are the plan root.
                if (planRoot == null)
                {
                    planRoot = createdNode;
                }

                try
                {
                    if (resolvedMapping.TargetMethod != null)
                    {
                        createdNode.PlannedMethod = resolvedMapping.TargetMethod;
                        plans[i] = createdNode;
                        continue;
                    }

                    if (resolvedMapping.TargetFactory)
                    {
                        var attribute = createdNode.Type.GetCustomAttribute <GeneratedFactoryAttribute>();
                        if (attribute == null)
                        {
                            // This node won't be valid because it's planned, has no value and
                            // has no constructor.
                            createdNode.InvalidHint = "The factory interface '" + createdNode.Type +
                                                      "' doesn't have a generated factory for it.  " +
                                                      "Make sure the factory interface inherits from " +
                                                      "IGenerateFactory so that the generator will " +
                                                      "implement it for you.";
                            plans[i] = createdNode;
                            continue;
                        }

                        var resolvedFactoryClass =
                            createdNode.Type.Assembly.GetTypes()
                            .FirstOrDefault(x => x.FullName == attribute.FullTypeName);
                        if (resolvedFactoryClass == null)
                        {
                            // This node won't be valid because it's planned, has no value and
                            // has no constructor.
                            createdNode.InvalidHint = "The generated factory class '" + attribute.FullTypeName +
                                                      "' could not be found in the assembly.";
                            plans[i] = createdNode;
                            continue;
                        }

                        // If the factory class is generic, pass in type parameters as needed.
                        if (resolvedFactoryClass != null && resolvedFactoryClass.IsGenericTypeDefinition)
                        {
                            resolvedFactoryClass = resolvedFactoryClass.MakeGenericType(requestedType.GenericTypeArguments);
                        }

                        createdNode.Type = resolvedFactoryClass;
                    }

                    if (createdNode.Type == null)
                    {
                        // This node won't be valid because it's planned, has no value and
                        // has no constructor.
                        createdNode.InvalidHint =
                            "There was no valid target for the binding (is the 'To' method missing?)";
                        plans[i] = createdNode;
                        continue;
                    }

                    if (createdNode.Type == requestedType && (requestedType.IsInterface || requestedType.IsAbstract))
                    {
                        // This node won't be valid because it's planned, has no value and
                        // has no constructor.
                        createdNode.InvalidHint =
                            "The target type '" + requestedType + "' isn't valid because it can't be constructed.";
                        plans[i] = createdNode;
                        continue;
                    }

                    createdNode.PlannedConstructor =
                        createdNode.Type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault();
                    if (createdNode.PlannedConstructor == null)
                    {
                        // This node won't be valid because it's planned, has no value and
                        // has no constructor.
                        createdNode.InvalidHint = "There was no valid public constructor for '" +
                                                  createdNode.Type.FullName + "'";
                        plans[i] = createdNode;
                        continue;
                    }

                    createdNode.PlannedConstructorArguments = new List <IUnresolvedArgument>();

                    var parameters = createdNode.PlannedConstructor.GetParameters();

                    var slots = new DefaultUnresolvedArgument[parameters.Length];

                    // First apply additional constructor arguments to the slots.
                    if (arguments != null)
                    {
                        foreach (var additional in arguments)
                        {
                            for (var s = 0; s < slots.Length; s++)
                            {
                                if (additional.Satisifies(createdNode.PlannedConstructor, parameters[s]))
                                {
                                    var plannedArgument = new DefaultUnresolvedArgument();
                                    plannedArgument.ArgumentType         = UnresolvedArgumentType.FactoryArgument;
                                    plannedArgument.FactoryArgumentValue = additional.GetValue();
                                    slots[s] = plannedArgument;
                                }
                            }
                        }
                    }

                    for (var ii = 0; ii < slots.Length; ii++)
                    {
                        if (slots[ii] != null)
                        {
                            // Already filled in.
                            continue;
                        }

                        var parameter = parameters[ii];

                        var plannedArgument = new DefaultUnresolvedArgument();
                        plannedArgument.ParameterName = parameter.Name;

                        if (parameter.ParameterType == typeof(ICurrentNode))
                        {
                            plannedArgument.ArgumentType = UnresolvedArgumentType.CurrentNode;
                            plannedArgument.CurrentNode  = new DefaultCurrentNode(createdNode);
                        }
                        else if (parameter.ParameterType == typeof(IKernel))
                        {
                            plannedArgument.ArgumentType = UnresolvedArgumentType.KnownValue;
                            plannedArgument.KnownValue   = this;
                        }
                        else
                        {
                            plannedArgument.ArgumentType   = UnresolvedArgumentType.Type;
                            plannedArgument.UnresolvedType = parameters[ii].ParameterType;
                            plannedArgument.ParameterName  = parameters[ii].GetCustomAttribute <NamedAttribute>()?.Name;
                            plannedArgument.IsOptional     = parameters[ii].GetCustomAttribute <OptionalAttribute>() != null;
                        }

                        slots[ii] = plannedArgument;
                    }

                    createdNode.PlannedConstructorArguments = new List <IUnresolvedArgument>(slots);

                    foreach (var argument in createdNode.PlannedConstructorArguments)
                    {
                        switch (argument.ArgumentType)
                        {
                        case UnresolvedArgumentType.Type:
                            if (argument.IsMultipleResult)
                            {
                                var children = CreatePlans(
                                    argument.MultipleResultElementType,
                                    createdNode,
                                    argument.ParameterName,
                                    planName,
                                    planRoot,
                                    null);
                                foreach (var child in children)
                                {
                                    if (child.ParentPlan == createdNode)
                                    {
                                        if (!createdNode.ChildrenInternal.Contains((INode)child))
                                        {
                                            createdNode.ChildrenInternal.Add((INode)child);
                                        }
                                    }
                                }
                                ((DefaultUnresolvedArgument)argument).PlannedTargets = children;
                            }
                            else
                            {
                                var child = CreatePlan(
                                    argument.UnresolvedType,
                                    createdNode,
                                    argument.ParameterName,
                                    planName,
                                    planRoot,
                                    null);
                                if (child.ParentPlan == createdNode)
                                {
                                    if (!createdNode.ChildrenInternal.Contains((INode)child))
                                    {
                                        createdNode.ChildrenInternal.Add((INode)child);
                                    }
                                }
                                ((DefaultUnresolvedArgument)argument).PlannedTarget = child;
                            }

                            break;
                        }
                    }

                    if (createdNode.Parent == null)
                    {
                        _hierarchy.RootNodes.Add(createdNode);
                    }
                    else
                    {
                        var childrenInternal = ((DefaultNode)scopeNode).ChildrenInternal;
                        if (!childrenInternal.Contains(createdNode))
                        {
                            childrenInternal.Add(createdNode);
                        }
                    }

                    plans[i] = createdNode;
                }
                finally
                {
                    planRoot.PlannedCreatedNodes.Add(createdNode);
                }
            }

            return(plans);
        }
示例#2
0
        private List <IPlan> CreatePlans(
#endif
            Type requestedType,
            INode current,
            string bindingName,
            string planName,
            INode planRoot,
            IInjectionAttribute[] injectionAttributes,
            IConstructorArgument[] arguments,
            Dictionary <Type, List <IMapping> > transientBindings)
        {
            injectionAttributes = injectionAttributes ?? new IInjectionAttribute[0];
            arguments           = arguments ?? new IConstructorArgument[0];

            // If the plan requires an existing node, we must defer resolution until the plan
            // has been fully formed.  For now, we create a node with Deferred set to
            // true, the requested type and desired scope node (if applicable).
            var requireExistingAttribute = injectionAttributes.OfType <RequireExistingAttribute>().FirstOrDefault();

            if (requireExistingAttribute != null)
            {
                if (planRoot == null)
                {
                    // We can't defer resolution on a plan root (it doesn't even make sense
                    // because there won't ever be anything to satisfy the request).
                    throw new InvalidOperationException(
                              "A plan root had a RequireExisting injection attribute, which " +
                              "can't ever be satisfied.");
                }

                var deferredSearchOptions = new List <KeyValuePair <Type, INode> >();

                // Add deferred search option if the current plan has a scope injection attribute.
                var scopeAttribute = injectionAttributes.OfType <ScopeAttribute>().FirstOrDefault();
                if (scopeAttribute != null)
                {
                    // We don't have a resolved mapping here, so we pass in null as the second argument.
                    var scopeNode = scopeAttribute.ScopeFromContext(current, null);
                    deferredSearchOptions.Add(new KeyValuePair <Type, INode>(
                                                  requestedType,
                                                  scopeNode));
                }

                // Add deferred search options based on explicit mappings in the kernel.
#if !PLATFORM_UNITY
                var requireResolvedMappings = await ResolveTypes(requestedType, bindingName, current, transientBindings);

                var requirePlans = (IPlan[])Activator.CreateInstance(typeof(IPlan <>).MakeGenericType(requestedType).MakeArrayType(), 1);
#else
                var requireResolvedMappings = ResolveTypes(requestedType, bindingName, current, transientBindings);
                var requirePlans            = new List <IPlan>(1);
                requirePlans.Add(null);
#endif
                foreach (var mapping in requireResolvedMappings)
                {
                    // The mechanism of adding additional desired types based on the bindings
                    // can only work for bindings that provide both a known target type, and
                    // a lifetime scope.
                    if (mapping.Target != null && mapping.LifetimeScope != null)
                    {
                        deferredSearchOptions.Add(new KeyValuePair <Type, INode>(
                                                      mapping.Target,
                                                      mapping.LifetimeScope.GetContainingNode()));
                    }
                }

                // Create the deferred node.
                Type nodeToCreate    = typeof(DefaultNode <>).MakeGenericType(requestedType);
                var createdNode      = (DefaultNode)Activator.CreateInstance(nodeToCreate);
                createdNode.Name     = string.Empty;
                createdNode.Parent   = current;
                createdNode.Planned  = true;
                createdNode.Deferred = true;
#if PLATFORM_UNITY
                createdNode.DeferredSearchOptions = deferredSearchOptions.ToDictionary(k => k.Key, v => v.Value);
#else
                createdNode.DeferredSearchOptions = deferredSearchOptions.AsReadOnly();
#endif
                createdNode.PlanName      = planName;
                createdNode.PlanRoot      = planRoot;
                createdNode.RequestedType = requestedType;

                // Add it to the list of deferred nodes on the plan root.
                planRoot.DeferredCreatedNodes.Add(createdNode);

                // Set the required plans and return it.
                requirePlans[0] = createdNode;
                return(requirePlans);
            }

            // Otherwise, construct plans based on the kernel configuration.
#if !PLATFORM_UNITY
            var resolvedMappings = await ResolveTypes(requestedType, bindingName, current, transientBindings);

            var plans = (IPlan[])Activator.CreateInstance(typeof(IPlan <>).MakeGenericType(requestedType).MakeArrayType(), resolvedMappings.Length);
#else
            var resolvedMappings = ResolveTypes(requestedType, bindingName, current, transientBindings);
            var plans            = new List <IPlan>(resolvedMappings.Length);
#endif
            for (var i = 0; i < resolvedMappings.Length; i++)
            {
#if PLATFORM_UNITY
                plans.Add(null);
#endif

                var resolvedMapping = resolvedMappings[i];
                var localPlanRoot   = planRoot;

                // If the resolved target is a generic type definition, we need to fill in the
                // generic type arguments from the request.
                var targetNonGeneric = resolvedMapping.Target;
                if (targetNonGeneric != null && targetNonGeneric.IsGenericTypeDefinition)
                {
#if !PLATFORM_UNITY
                    targetNonGeneric = targetNonGeneric.MakeGenericType(requestedType.GenericTypeArguments);
#else
                    targetNonGeneric = targetNonGeneric.MakeGenericType(requestedType.GetGenericArguments());
#endif
                }

                // Use the current node as the scope, unless the binding overrides the scope.
                var scopeNode      = current;
                var uniquePerScope = resolvedMapping.UniquePerScope;
                if (resolvedMapping.LifetimeScope != null)
                {
                    scopeNode = resolvedMapping.LifetimeScope.GetContainingNode();
                }

                // If the parameter or injection location has a scope attribute, that overrides
                // the bindings default scope.
                var scopeAttribute = injectionAttributes.OfType <ScopeAttribute>().FirstOrDefault();
                if (scopeAttribute != null)
                {
                    scopeNode      = scopeAttribute.ScopeFromContext(current, resolvedMapping);
                    uniquePerScope = scopeAttribute.UniquePerScope;
                }

                // If the binding is set to be unique per scope, find an existing plan for
                // this binding in the current scope if one exists.
                if (scopeNode != null && uniquePerScope)
                {
                    var existing =
                        scopeNode.Children.FirstOrDefault(x => x.Type != null && x.Type.IsAssignableFrom(targetNonGeneric));
                    if (existing != null)
                    {
                        if (existing.Planned && existing.PlanRoot != localPlanRoot)
                        {
                            // Flag that the plan root is now dependent on the other
                            // plan being resolved.
                            if (localPlanRoot != null)
                            {
                                localPlanRoot.DependentOnPlans.Add(existing.PlanRoot);
                            }
                        }

                        plans[i] = existing;
                        continue;
                    }
                }

                Type nodeToCreate;
                if (targetNonGeneric != null)
                {
                    nodeToCreate = typeof(DefaultNode <>).MakeGenericType(targetNonGeneric);
                }
                else
                {
                    nodeToCreate = typeof(DefaultNode <>).MakeGenericType(requestedType);
                }
                var createdNode           = (DefaultNode)Activator.CreateInstance(nodeToCreate);
                createdNode.Name          = string.Empty;
                createdNode.Parent        = scopeNode;
                createdNode.Planned       = true;
                createdNode.Type          = targetNonGeneric ?? requestedType;
                createdNode.PlanName      = planName;
                createdNode.PlanRoot      = localPlanRoot;
                createdNode.RequestedType = requestedType;

                if (createdNode.Type.ContainsGenericParameters)
                {
                    throw new InvalidOperationException("The type still contained generic type parameters even after initial binding resolution.");
                }

                // If there is no plan root, then we are the plan root.
                if (localPlanRoot == null)
                {
                    localPlanRoot = createdNode;
                }

                try
                {
                    if (resolvedMapping.DiscardNodeOnResolve)
                    {
                        // We discard this node from the hierarchy once the plan is resolved or discarded.
                        localPlanRoot.DiscardOnResolve.Add(createdNode);
                    }

                    if (resolvedMapping.TargetMethod != null)
                    {
                        createdNode.PlannedMethod = resolvedMapping.TargetMethod;
                        plans[i] = createdNode;
                        continue;
                    }

                    if (resolvedMapping.TargetFactory)
                    {
                        var attribute = createdNode.Type.GetCustomAttribute <GeneratedFactoryAttribute>();
                        if (attribute == null)
                        {
                            // This node won't be valid because it's planned, has no value and
                            // has no constructor.
                            createdNode.InvalidHint = "The factory interface '" + createdNode.Type +
                                                      "' doesn't have a generated factory for it.  " +
                                                      "Make sure the factory interface inherits from " +
                                                      "IGenerateFactory so that the generator will " +
                                                      "implement it for you.";
                            plans[i] = createdNode;
                            continue;
                        }

                        var targetName = resolvedMapping.TargetFactoryNotSupported
                            ? attribute.NotSupportedFullTypeName
                            : attribute.FullTypeName;

#if !PLATFORM_UNITY
                        var resolvedFactoryClass = (await GetTypeForAssembly(createdNode.Type.Assembly, targetName));
#else
                        var resolvedFactoryClass = (GetTypeForAssembly(createdNode.Type.Assembly, targetName));
#endif
                        if (resolvedFactoryClass == null)
                        {
                            // This node won't be valid because it's planned, has no value and
                            // has no constructor.
                            createdNode.InvalidHint = "The generated factory class '" + targetName +
                                                      "' could not be found in the assembly.";
                            plans[i] = createdNode;
                            continue;
                        }

                        // If the factory class is generic, pass in type parameters as needed.
                        if (resolvedFactoryClass != null && resolvedFactoryClass.IsGenericTypeDefinition)
                        {
#if !PLATFORM_UNITY
                            resolvedFactoryClass = resolvedFactoryClass.MakeGenericType(requestedType.GenericTypeArguments);
#else
                            resolvedFactoryClass = resolvedFactoryClass.MakeGenericType(requestedType.GetGenericArguments());
#endif
                        }

                        createdNode.Type = resolvedFactoryClass;
                    }

                    if (createdNode.Type == null)
                    {
                        // This node won't be valid because it's planned, has no value and
                        // has no constructor.
                        createdNode.InvalidHint =
                            "There was no valid target for the binding (is the 'To' method missing?)";
                        plans[i] = createdNode;
                        continue;
                    }

                    if (createdNode.Type == requestedType && (requestedType.IsInterface || requestedType.IsAbstract))
                    {
                        // This node won't be valid because it's planned, has no value and
                        // has no constructor.
                        createdNode.InvalidHint =
                            "The target type '" + requestedType + "' isn't valid because it can't be constructed.";
                        plans[i] = createdNode;
                        continue;
                    }

                    createdNode.PlannedConstructor =
                        createdNode.Type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault();
                    if (createdNode.PlannedConstructor == null)
                    {
                        // This node won't be valid because it's planned, has no value and
                        // has no constructor.
                        createdNode.InvalidHint = "There was no valid public constructor for '" +
                                                  createdNode.Type.FullName + "'";
                        plans[i] = createdNode;
                        continue;
                    }

                    createdNode.PlannedConstructorArguments = new List <IUnresolvedArgument>();

                    var parameters = createdNode.PlannedConstructor.GetParameters();

                    var slots = new DefaultUnresolvedArgument[parameters.Length];

                    // First apply additional constructor arguments to the slots.
                    if (arguments != null)
                    {
                        foreach (var additional in arguments)
                        {
                            for (var s = 0; s < slots.Length; s++)
                            {
                                if (additional.Satisifies(createdNode.PlannedConstructor, parameters[s]))
                                {
                                    var plannedArgument                  = new DefaultUnresolvedArgument();
                                    plannedArgument.ArgumentType         = UnresolvedArgumentType.FactoryArgument;
                                    plannedArgument.FactoryArgumentValue = additional.GetValue();
                                    slots[s] = plannedArgument;
                                }
                            }
                        }
                    }

                    for (var ii = 0; ii < slots.Length; ii++)
                    {
                        if (slots[ii] != null)
                        {
                            // Already filled in.
                            continue;
                        }

                        var parameter = parameters[ii];

                        var plannedArgument = new DefaultUnresolvedArgument();

                        if (parameter.ParameterType == typeof(ICurrentNode))
                        {
                            plannedArgument.ArgumentType = UnresolvedArgumentType.CurrentNode;
                            plannedArgument.CurrentNode  = new DefaultCurrentNode(createdNode);
                        }
                        else if (parameter.ParameterType == typeof(INode))
                        {
                            plannedArgument.ArgumentType = UnresolvedArgumentType.Node;
                            plannedArgument.Node         = createdNode;
                        }
                        else if (parameter.ParameterType == typeof(IHierarchy))
                        {
                            plannedArgument.ArgumentType = UnresolvedArgumentType.Hierarchy;
                            plannedArgument.Hierarchy    = _hierarchy;
                        }
                        else if (parameter.ParameterType == typeof(IKernel))
                        {
                            plannedArgument.ArgumentType = UnresolvedArgumentType.KnownValue;
                            plannedArgument.KnownValue   = this;
                        }
                        else
                        {
                            plannedArgument.ArgumentType        = UnresolvedArgumentType.Type;
                            plannedArgument.UnresolvedType      = parameters[ii].ParameterType;
                            plannedArgument.InjectionParameters =
                                parameters[ii].GetCustomAttributes(true).OfType <IInjectionAttribute>().ToArray();
                            var namedAttribute   = plannedArgument.InjectionParameters.OfType <NamedAttribute>().FirstOrDefault();
                            plannedArgument.Name = namedAttribute == null ? null : namedAttribute.Name;
                        }

                        slots[ii] = plannedArgument;
                    }

                    createdNode.PlannedConstructorArguments = new List <IUnresolvedArgument>(slots);

                    foreach (var argument in createdNode.PlannedConstructorArguments)
                    {
                        switch (argument.ArgumentType)
                        {
                        case UnresolvedArgumentType.Type:
                            if (argument.IsMultipleResult)
                            {
#if !PLATFORM_UNITY
                                var children = await CreatePlans(
#else
                                var children = CreatePlans(
#endif
                                    argument.MultipleResultElementType,
                                    createdNode,
                                    argument.Name,
                                    planName,
                                    localPlanRoot,
                                    argument.InjectionParameters,
                                    null,
                                    transientBindings);

                                foreach (var child in children)
                                {
                                    if (child.ParentPlan == createdNode)
                                    {
                                        _hierarchy.AddChildNode(createdNode, (INode)child);
                                    }
                                }
                                ((DefaultUnresolvedArgument)argument).PlannedTargets = children;
                            }
                            else
                            {
#if !PLATFORM_UNITY
                                var child = await CreatePlan(
#else
                                var child = CreatePlan(
#endif
                                    argument.UnresolvedType,
                                    createdNode,
                                    argument.Name,
                                    planName,
                                    localPlanRoot,
                                    argument.InjectionParameters,
                                    null,
                                    transientBindings);

                                if (child.ParentPlan == createdNode)
                                {
                                    _hierarchy.AddChildNode(createdNode, (INode)child);
                                }
                                ((DefaultUnresolvedArgument)argument).PlannedTarget = child;
                            }

                            break;
                        }
                    }

                    if (createdNode.Parent == null)
                    {
                        _hierarchy.AddRootNode(createdNode);
                    }
                    else
                    {
                        _hierarchy.AddChildNode(scopeNode, createdNode);
                    }

                    plans[i] = createdNode;
                }
                finally
                {
                    localPlanRoot.PlannedCreatedNodes.Add(createdNode);
                }
            }

            // If we are the plan root, go back through all of the nodes we deferred and try to
            // resolve them now that the plan has been fully created.
            if (planRoot != null && planRoot == current)
            {
                foreach (var deferred in planRoot.DeferredCreatedNodes)
                {
                    // Search the deferred options.
                    foreach (var searchOption in deferred.DeferredSearchOptions)
                    {
                        var type = searchOption.Key;
                        var scopeNode = searchOption.Value;

                        var existing =
                            scopeNode.Children.FirstOrDefault(x => x.Type != null && type.IsAssignableFrom(x.Type));
                        if (existing != null)
                        {
                            if (existing.Planned && existing.PlanRoot != planRoot)
                            {
                                // Flag that the plan root is now dependent on the other
                                // plan being resolved.
                                if (planRoot != null)
                                {
                                    planRoot.DependentOnPlans.Add(existing.PlanRoot);
                                }
                            }

                            // Set the existing node as the deferred target.
                            ((DefaultNode)deferred).DeferredResolvedTarget = existing;
                            break;
                        }
                    }

                    // If this deferred node doesn't have any deferred search options, give a
                    // more tailored error.
                    if (deferred.DeferredSearchOptions.Count == 0)
                    {
                        ((DefaultNode)deferred).InvalidHint =
                            "This node was deferred because it depends on an existing node " +
                            "being in the tree, however, no search options were provided on " +
                            "the deferred node.  This indicates that you have a parameter that " +
                            "specifies [RequireExisting], but has no explicit scope set on the " +
                            "parameter, and no explicit kernel bindings for '" + deferred.RequestedType + "' " +
                            "which also provide scopes.  The deferred node can not be resolved.";
                    }

                    // If we didn't find a resolved target for this deferred node, invalidate
                    // the deferred node.
                    if (deferred.DeferredResolvedTarget == null)
                    {
                        ((DefaultNode)deferred).InvalidHint =
                            "This node was deferred because it depends on an existing node " +
                            "being in the tree, however, no search options yielded a resolution " +
                            "for the node.  This usually indicates that an implementation was " +
                            "expecting you to declare a dependent service elsewhere in the " +
                            "hierarchy, but you haven't done so.  The request was looking for one of: \r\n" +
                            deferred.DeferredSearchOptions
                            .Select(x => " * A '" + x.Key.FullName + "' within '" + x.Value.FullName + "'")
                            .Aggregate((a, b) => a + "\r\n" + b);
                    }
                }
            }

            return(plans);
        }