// At end of parse, removes and returns all remaining simple fixups, whether or not they // are resolved public IEnumerable <NameFixupToken> GetRemainingSimpleFixups() { foreach (object key in _dependenciesByParentObject.Keys) { _uninitializedObjectsAtParseEnd.Add(key); } List <string> names = new List <string>(_dependenciesByName.Keys); foreach (string name in names) { FrugalObjectList <NameFixupToken> dependencies = _dependenciesByName[name]; int i = 0; while (i < dependencies.Count) { NameFixupToken token = dependencies[i]; if (!token.CanAssignDirectly) { i++; continue; } dependencies.RemoveAt(i); if (dependencies.Count == 0) { _dependenciesByName.Remove(name); } RemoveTokenByParent(token); yield return(token); } } }
public IEnumerable <NameFixupToken> GetRemainingSimpleFixups() { foreach (object obj2 in this._dependenciesByParentObject.Keys) { this._uninitializedObjectsAtParseEnd.Add(obj2); } List <string> iteratorVariable0 = new List <string>(this._dependenciesByName.Keys); foreach (string iteratorVariable1 in iteratorVariable0) { FrugalObjectList <NameFixupToken> iteratorVariable2 = this._dependenciesByName[iteratorVariable1]; int index = 0; while (index < iteratorVariable2.Count) { NameFixupToken token = iteratorVariable2[index]; if (!token.CanAssignDirectly) { index++; continue; } iteratorVariable2.RemoveAt(index); if (iteratorVariable2.Count == 0) { this._dependenciesByName.Remove(iteratorVariable1); } this.RemoveTokenByParent(token); yield return(token); } } }
// Finds the names that this object's subtree is blocked on. public void GetDependentNames(object instance, List <string> result) { // We're only interested in the immediate subtree, not named-references to other subtrees // that might exist but not be fully initialized. So we only follow UnresolvedChildren and // MarkupExtensionFirstRun edges, which means there is no risk of cycles FrugalObjectList <NameFixupToken> dependencies; if (!_dependenciesByParentObject.TryGetValue(instance, out dependencies)) { return; } for (int i = 0; i < dependencies.Count; i++) { NameFixupToken token = dependencies[i]; if (token.FixupType == FixupType.MarkupExtensionFirstRun || token.FixupType == FixupType.UnresolvedChildren) { GetDependentNames(token.ReferencedObject, result); } else if (token.NeededNames != null) { foreach (string name in token.NeededNames) { if (!result.Contains(name)) { result.Add(name); } } } } }
private bool FindDependencies(NameFixupToken inEdge, List <NameFixupToken> alreadyTraversed) { if (!alreadyTraversed.Contains(inEdge)) { FrugalObjectList <NameFixupToken> list; alreadyTraversed.Add(inEdge); if ((inEdge.ReferencedObject == null) || !this._dependenciesByParentObject.TryGetValue(inEdge.ReferencedObject, out list)) { return(true); } for (int i = 0; i < list.Count; i++) { NameFixupToken token = list[i]; if (token.FixupType == FixupType.MarkupExtensionFirstRun) { return(false); } if (!this.FindDependencies(token, alreadyTraversed)) { return(false); } } } return(true); }
// Depth-first traversal of the graph starting at a given edge. Ignores edges that would cause cycles. // Returns true if the dependency list is complete, false if we aborted because we found an ME. private bool FindDependencies(NameFixupToken inEdge, List <NameFixupToken> alreadyTraversed) { if (alreadyTraversed.Contains(inEdge)) { // Cycle, skip it return(true); } alreadyTraversed.Add(inEdge); FrugalObjectList <NameFixupToken> outEdges; if (inEdge.ReferencedObject == null || !_dependenciesByParentObject.TryGetValue(inEdge.ReferencedObject, out outEdges)) { // No dependencies, we're done with this subgraph return(true); } for (int i = 0; i < outEdges.Count; i++) { NameFixupToken outEdge = outEdges[i]; if (outEdge.FixupType == FixupType.MarkupExtensionFirstRun) { return(false); } Debug.Assert(outEdge.FixupType == FixupType.UnresolvedChildren); if (!FindDependencies(outEdge, alreadyTraversed)) { return(false); } } return(true); }
public void GetDependentNames(object instance, List <string> result) { FrugalObjectList <NameFixupToken> list; if (this._dependenciesByParentObject.TryGetValue(instance, out list)) { for (int i = 0; i < list.Count; i++) { NameFixupToken token = list[i]; if ((token.FixupType == FixupType.MarkupExtensionFirstRun) || (token.FixupType == FixupType.UnresolvedChildren)) { this.GetDependentNames(token.ReferencedObject, result); } else if (token.NeededNames != null) { foreach (string str in token.NeededNames) { if (!result.Contains(str)) { result.Add(str); } } } } } }
public void AddEndOfParseDependency(object childThatHasUnresolvedChildren, FixupTarget parentObject) { NameFixupToken token = new NameFixupToken { Target = parentObject, FixupType = FixupType.UnresolvedChildren, ReferencedObject = childThatHasUnresolvedChildren }; AddToMultiDict <object>(this._dependenciesByParentObject, parentObject.Instance, token); }
public void AddEndOfParseDependency(object childThatHasUnresolvedChildren, FixupTarget parentObject) { NameFixupToken token = new NameFixupToken(); token.Target = parentObject; token.FixupType = FixupType.UnresolvedChildren; token.ReferencedObject = childThatHasUnresolvedChildren; AddToMultiDict(_dependenciesByParentObject, parentObject.Instance, token); // We don't add to the _dependenciesByChildObject, because at end-of-parse, a single // child object can be a dependency of multiple parents }
// Remove a resolved dependency from the graph. // Enqueues all removed edges so that the ObjectWriter can process the dependents // (rerun converters, apply simple fixups, call EndInit on parent ojects, etc). public void ResolveDependenciesTo(object instance, string name) { // Remove any dependency on this instance NameFixupToken token = null; if (instance != null) { if (_dependenciesByChildObject.TryGetValue(instance, out token)) { _dependenciesByChildObject.Remove(instance); RemoveTokenByParent(token); _resolvedTokensPendingProcessing.Enqueue(token); } } // Remove any dependencies on this name, and return any tokens whose dependencies // have all been resolved. FrugalObjectList <NameFixupToken> nameDependencies; if (name != null && _dependenciesByName.TryGetValue(name, out nameDependencies)) { int i = 0; while (i < nameDependencies.Count) { token = nameDependencies[i]; // The same name can occur in multiple namescopes, so we need to make sure that // this named object is visible in the scope of the token. object resolvedName = token.ResolveName(name); if (instance != resolvedName) { i++; continue; } if (token.CanAssignDirectly) { // For simple fixups, we need to return the resolved object token.ReferencedObject = instance; } token.NeededNames.Remove(name); nameDependencies.RemoveAt(i); if (nameDependencies.Count == 0) { _dependenciesByName.Remove(name); } if (token.NeededNames.Count == 0) { RemoveTokenByParent(token); _resolvedTokensPendingProcessing.Enqueue(token); } } } }
private static void AddToMultiDict <TKey>(Dictionary <TKey, FrugalObjectList <NameFixupToken> > dict, TKey key, NameFixupToken value) { FrugalObjectList <NameFixupToken> tokenList; if (!dict.TryGetValue(key, out tokenList)) { tokenList = new FrugalObjectList <NameFixupToken>(1); dict.Add(key, tokenList); } tokenList.Add(value); }
private void RemoveTokenByParent(NameFixupToken token) { object instance = token.Target.Instance; FrugalObjectList <NameFixupToken> list = this._dependenciesByParentObject[instance]; if (list.Count == 1) { this._dependenciesByParentObject.Remove(instance); } else { list.Remove(token); } }
private void RemoveTokenByParent(NameFixupToken token) { object parentInstance = token.Target.Instance; FrugalObjectList <NameFixupToken> parentDependencies = _dependenciesByParentObject[parentInstance]; Debug.Assert(parentDependencies.Contains(token)); if (parentDependencies.Count == 1) { _dependenciesByParentObject.Remove(parentInstance); } else { parentDependencies.Remove(token); } }
// Add an edge to the graph. We need to look up edges in both directions, so each edge is // stored in two dictionaries. public void AddDependency(NameFixupToken fixupToken) { // Need to special case a deferred ProvideValue at the root, because it has no parent if (fixupToken.Target.Property == null) { Debug.Assert(fixupToken.Target.Instance == null && fixupToken.Target.InstanceType == null && fixupToken.FixupType == FixupType.MarkupExtensionFirstRun); Debug.Assert(_deferredRootProvideValue == null); _deferredRootProvideValue = fixupToken; return; } object parentObject = fixupToken.Target.Instance; // References aren't allowed in non-instantiating directives, except for: // - Initialization, in which case FixupTarget.Instance is the object whose property the // initialized object will be assigned to; and // - Key, in which case the FixupTarget.Instance is the dictionary Debug.Assert(parentObject != null); AddToMultiDict(_dependenciesByParentObject, parentObject, fixupToken); if (fixupToken.ReferencedObject != null) { Debug.Assert(fixupToken.FixupType == FixupType.UnresolvedChildren || fixupToken.FixupType == FixupType.MarkupExtensionFirstRun); // These fixups are only used for the immediate parent of the object, so there can // only be one per child instance Debug.Assert(!_dependenciesByChildObject.ContainsKey(fixupToken.ReferencedObject)); _dependenciesByChildObject.Add(fixupToken.ReferencedObject, fixupToken); } else { Debug.Assert(fixupToken.FixupType != FixupType.UnresolvedChildren && fixupToken.FixupType != FixupType.MarkupExtensionFirstRun); foreach (string name in fixupToken.NeededNames) { AddToMultiDict(_dependenciesByName, name, fixupToken); } } }
public void ResolveDependenciesTo(object instance, string name) { NameFixupToken token = null; FrugalObjectList <NameFixupToken> list; if ((instance != null) && this._dependenciesByChildObject.TryGetValue(instance, out token)) { this._dependenciesByChildObject.Remove(instance); this.RemoveTokenByParent(token); this._resolvedTokensPendingProcessing.Enqueue(token); } if ((name != null) && this._dependenciesByName.TryGetValue(name, out list)) { int index = 0; while (index < list.Count) { token = list[index]; object obj2 = token.ResolveName(name); if (instance != obj2) { index++; } else { if (token.CanAssignDirectly) { token.ReferencedObject = instance; } token.NeededNames.Remove(name); list.RemoveAt(index); if (list.Count == 0) { this._dependenciesByName.Remove(name); } if (token.NeededNames.Count == 0) { this.RemoveTokenByParent(token); this._resolvedTokensPendingProcessing.Enqueue(token); } } } } }
// At end of parse, removes and returns all remaining reparse fixups, whether or not they // are resolved. Assumes that all simple fixups have already been removed. public IEnumerable <NameFixupToken> GetRemainingReparses() { List <object> parentObjs = new List <object>(_dependenciesByParentObject.Keys); foreach (object parentObj in parentObjs) { FrugalObjectList <NameFixupToken> dependencies = _dependenciesByParentObject[parentObj]; int i = 0; while (i < dependencies.Count) { NameFixupToken token = dependencies[i]; if (token.FixupType == FixupType.MarkupExtensionFirstRun || token.FixupType == FixupType.UnresolvedChildren) { i++; continue; } // Remove this token from the _dependenciesByParentObject dictionary dependencies.RemoveAt(i); if (dependencies.Count == 0) { _dependenciesByParentObject.Remove(parentObj); } // Remove this token from the _dependenciesByName dictionary foreach (string name in token.NeededNames) { FrugalObjectList <NameFixupToken> nameDependencies = _dependenciesByName[name]; if (nameDependencies.Count == 1) { nameDependencies.Remove(token); } else { _dependenciesByName.Remove(name); } } yield return(token); } } }
public void AddDependency(NameFixupToken fixupToken) { if (fixupToken.Target.Property == null) { this._deferredRootProvideValue = fixupToken; } else { object instance = fixupToken.Target.Instance; AddToMultiDict <object>(this._dependenciesByParentObject, instance, fixupToken); if (fixupToken.ReferencedObject != null) { this._dependenciesByChildObject.Add(fixupToken.ReferencedObject, fixupToken); } else { foreach (string str in fixupToken.NeededNames) { AddToMultiDict <string>(this._dependenciesByName, str, fixupToken); } } } }
public IEnumerable <NameFixupToken> GetRemainingReparses() { List <object> iteratorVariable0 = new List <object>(this._dependenciesByParentObject.Keys); foreach (object iteratorVariable1 in iteratorVariable0) { FrugalObjectList <NameFixupToken> iteratorVariable2 = this._dependenciesByParentObject[iteratorVariable1]; int index = 0; while (index < iteratorVariable2.Count) { NameFixupToken iteratorVariable4 = iteratorVariable2[index]; if ((iteratorVariable4.FixupType == FixupType.MarkupExtensionFirstRun) || (iteratorVariable4.FixupType == FixupType.UnresolvedChildren)) { index++; continue; } iteratorVariable2.RemoveAt(index); if (iteratorVariable2.Count == 0) { this._dependenciesByParentObject.Remove(iteratorVariable1); } foreach (string str in iteratorVariable4.NeededNames) { FrugalObjectList <NameFixupToken> list = this._dependenciesByName[str]; if (list.Count == 1) { list.Remove(iteratorVariable4); } else { this._dependenciesByName.Remove(str); } } yield return(iteratorVariable4); } } }
private NameFixupToken GetTokenForUnresolvedChildren(object childThatHasUnresolvedChildren, XamlMember property, XamlSavedContext deferredMarkupExtensionContext) { NameFixupToken token = new NameFixupToken(); if (deferredMarkupExtensionContext != null) { token.FixupType = FixupType.MarkupExtensionFirstRun; token.SavedContext = deferredMarkupExtensionContext; } else { token.FixupType = FixupType.UnresolvedChildren; } token.ReferencedObject = childThatHasUnresolvedChildren; token.Target.Property = property; return token; }
private void ProcessNameFixup_UpdatePendingAddKey(NameFixupToken token, object key) { if (token.Target.KeyHolder != null) { token.Target.KeyHolder.Key = key; } else if (token.Target.TemporaryCollectionIndex >= 0) { List<PendingCollectionAdd> list = this.PendingCollectionAdds[token.Target.Instance]; PendingCollectionAdd add = list[token.Target.TemporaryCollectionIndex]; add.Key = key; add.KeyIsSet = true; } }
private void ProcessNameFixup_UpdatePendingAddItem(NameFixupToken token, object item) { List<PendingCollectionAdd> list = this.PendingCollectionAdds[token.Target.Instance]; PendingCollectionAdd add = list[token.Target.TemporaryCollectionIndex]; add.Item = item; if (!(item is NameFixupToken)) { add.ItemType = (item != null) ? this.GetXamlType(item.GetType()) : null; } }
private void ProcessNameFixup_Simple(NameFixupToken token) { object referencedObject = token.ReferencedObject; if (token.Target.Property == XamlLanguage.Key) { this.ProcessNameFixup_UpdatePendingAddKey(token, referencedObject); } else if (token.Target.Property == XamlLanguage.Items) { this.ProcessNameFixup_UpdatePendingAddItem(token, referencedObject); } else { this.SetValue(token.Target.Instance, token.Target.Property, referencedObject); } }
private void ProcessNameFixup_Reparse(NameFixupToken token, bool nameResolutionIsComplete) { object obj2 = null; ObjectWriterContext targetContext = token.TargetContext; targetContext.NameResolutionComplete = nameResolutionIsComplete; targetContext.IsInitializedCallback = this; switch (token.FixupType) { case FixupType.MarkupExtensionFirstRun: if (!this.Logic_ProvideValue(targetContext)) { break; } return; case FixupType.MarkupExtensionRerun: obj2 = this.Runtime.CallProvideValue((MarkupExtension) targetContext.CurrentInstance, targetContext.ServiceProviderContext); targetContext.CurrentInstance = obj2; break; case FixupType.PropertyValue: obj2 = this.Logic_CreateFromValue(targetContext, targetContext.ParentProperty.TypeConverter, targetContext.CurrentInstance, targetContext.ParentProperty, targetContext.ParentProperty.Name, token); token.TargetContext.CurrentInstance = obj2; break; case FixupType.ObjectInitializationValue: this.Logic_CreateFromInitializationValue(targetContext); if (token.TargetContext.CurrentInstanceRegisteredName != null) { this.Logic_RegisterName_OnCurrent(token.TargetContext, token.TargetContext.CurrentInstanceRegisteredName); } break; } if (token.Target.Property == XamlLanguage.Key) { this.ProcessNameFixup_UpdatePendingAddKey(token, targetContext.CurrentInstance); } else if (token.Target.Property == XamlLanguage.Items) { this.ProcessNameFixup_UpdatePendingAddItem(token, targetContext.CurrentInstance); } else if (token.Target.Property != null) { this.Logic_DoAssignmentToParentProperty(targetContext); } else { this._lastInstance = targetContext.CurrentInstance; } NameFixupToken currentInstance = targetContext.CurrentInstance as NameFixupToken; if (currentInstance != null) { currentInstance.Target = token.Target; currentInstance.LineNumber = token.LineNumber; currentInstance.LinePosition = token.LinePosition; if ((token.Target.Property == XamlLanguage.Key) || (token.Target.Property == XamlLanguage.Items)) { this._nameFixupGraph.AddDependency(currentInstance); } } }
private void ProcessNameFixup(NameFixupToken token, bool nameResolutionIsComplete) { IAddLineInfo lineInfo = this.Runtime.LineInfo; try { this.Runtime.LineInfo = token; if (token.CanAssignDirectly) { this.ProcessNameFixup_Simple(token); } else if (token.FixupType != FixupType.UnresolvedChildren) { this.ProcessNameFixup_Reparse(token, nameResolutionIsComplete); } } finally { this.Runtime.LineInfo = lineInfo; } }
private void PendCurrentFixupToken_SetValue(NameFixupToken token) { token.LineNumber = this._lineNumber; token.LinePosition = this._linePosition; token.Runtime = this.Runtime; this.NameFixupGraph.AddDependency(token); }
private void Logic_PendKeyFixupToken(ObjectWriterContext ctx, NameFixupToken token) { token.Target.Instance = ctx.GrandParentInstance; token.Target.InstanceType = ctx.GrandParentType; token.Target.InstanceWasGotten = ctx.GrandParentIsObjectFromMember; FixupTargetKeyHolder holder = new FixupTargetKeyHolder(token); token.Target.KeyHolder = holder; ctx.ParentKey = holder; if (token.Target.Instance != null) { this.PendCurrentFixupToken_SetValue(token); } }
object IXamlNameResolver.GetFixupToken(IEnumerable<string> names, bool canAssignDirectly) { if (this._xamlContext.NameResolutionComplete) { return null; } NameFixupToken token = new NameFixupToken { CanAssignDirectly = canAssignDirectly }; token.NeededNames.AddRange(names); if (token.CanAssignDirectly && (token.NeededNames.Count != 1)) { throw new ArgumentException(System.Xaml.SR.Get("SimpleFixupsMustHaveOneName"), "names"); } if (this._xamlContext.CurrentType == null) { if (this._xamlContext.ParentProperty == XamlLanguage.Initialization) { token.FixupType = FixupType.ObjectInitializationValue; token.Target.Instance = this._xamlContext.GrandParentInstance; token.Target.InstanceWasGotten = this._xamlContext.GrandParentIsObjectFromMember; token.Target.InstanceType = this._xamlContext.GrandParentType; token.Target.Property = this._xamlContext.GrandParentProperty; } else { token.FixupType = FixupType.PropertyValue; token.Target.Instance = this._xamlContext.ParentInstance; token.Target.InstanceWasGotten = this._xamlContext.ParentIsObjectFromMember; token.Target.InstanceType = this._xamlContext.ParentType; token.Target.Property = this._xamlContext.ParentProperty; } } else { token.FixupType = FixupType.MarkupExtensionRerun; token.Target.Instance = this._xamlContext.ParentInstance; token.Target.InstanceWasGotten = this._xamlContext.ParentIsObjectFromMember; token.Target.InstanceType = this._xamlContext.ParentType; token.Target.Property = this._xamlContext.ParentProperty; } if (token.CanAssignDirectly) { token.NameScopeDictionaryList.AddRange(this._xamlContext.StackWalkOfNameScopes); return token; } token.SavedContext = this._xamlContext.GetSavedContext((token.FixupType == FixupType.MarkupExtensionRerun) ? SavedContextType.ReparseMarkupExtension : SavedContextType.ReparseValue); return token; }
public IEnumerable <NameFixupToken> GetRemainingObjectDependencies() { List <NameFixupToken> markupExtensionTokens = new List <NameFixupToken>(); foreach (NameFixupToken token in this._dependenciesByChildObject.Values) { if (token.FixupType == FixupType.MarkupExtensionFirstRun) { markupExtensionTokens.Add(token); } } while (markupExtensionTokens.Count > 0) { bool iteratorVariable1 = false; int index = 0; while (index < markupExtensionTokens.Count) { NameFixupToken inEdge = markupExtensionTokens[index]; List <NameFixupToken> alreadyTraversed = new List <NameFixupToken>(); if (!this.FindDependencies(inEdge, alreadyTraversed)) { index++; } else { for (int i = alreadyTraversed.Count - 1; i >= 0; i--) { NameFixupToken iteratorVariable6 = alreadyTraversed[i]; this.RemoveTokenByParent(iteratorVariable6); yield return(iteratorVariable6); } iteratorVariable1 = true; markupExtensionTokens.RemoveAt(index); } } if (!iteratorVariable1) { ThrowProvideValueCycle(markupExtensionTokens); } } while (this._dependenciesByParentObject.Count > 0) { FrugalObjectList <NameFixupToken> iteratorVariable7 = null; foreach (FrugalObjectList <NameFixupToken> list in this._dependenciesByParentObject.Values) { iteratorVariable7 = list; break; } for (int j = 0; j < iteratorVariable7.Count; j++) { List <NameFixupToken> iteratorVariable9 = new List <NameFixupToken>(); this.FindDependencies(iteratorVariable7[j], iteratorVariable9); for (int k = iteratorVariable9.Count - 1; k >= 0; k--) { NameFixupToken iteratorVariable11 = iteratorVariable9[k]; this.RemoveTokenByParent(iteratorVariable11); yield return(iteratorVariable11); } } } if (this._deferredRootProvideValue != null) { yield return(this._deferredRootProvideValue); } else { yield break; } }
// At end of parse, removes and returns all remaining MarkupExtensionFirstRun and UnresolvedChildren // tokens, even if they are not fully initialized. Assumes that all simple fixups and reparses have // already been removed. public IEnumerable <NameFixupToken> GetRemainingObjectDependencies() { // We'd like to return dependencies in a topologically sorted order, but the graph is // not acylic. (If it were, all references would have been resolved during the regular parse.) // However, we don't allow ProvideValue cycles. So find a MarkupExtension that doesn't have // dependencies on any other MarkupExtension. // Note: at this point we can't use _dependenciesByChildObject for general traversal, // because it's not updated by AddEndOfParseDependency. However, AddEndOfParseDependency // doesn't add MarkupExtension edges, so we can still use _dependenciesByChildObject for that. List <NameFixupToken> markupExtensionTokens = new List <NameFixupToken>(); foreach (NameFixupToken curToken in _dependenciesByChildObject.Values) { if (curToken.FixupType == FixupType.MarkupExtensionFirstRun) { markupExtensionTokens.Add(curToken); } } while (markupExtensionTokens.Count > 0) { bool found = false; int i = 0; while (i < markupExtensionTokens.Count) { NameFixupToken meToken = markupExtensionTokens[i]; List <NameFixupToken> dependencies = new List <NameFixupToken>(); if (!FindDependencies(meToken, dependencies)) { i++; continue; } // Iterate the list in backwards order, so we return the deepest first for (int j = dependencies.Count - 1; j >= 0; j--) { NameFixupToken token = dependencies[j]; RemoveTokenByParent(token); yield return(token); } found = true; markupExtensionTokens.RemoveAt(i); } if (!found) { // We have MEs left, but they all have dependencies on other MEs. // That means we have a cycle. ThrowProvideValueCycle(markupExtensionTokens); } } // For the remaining EndInits, we pick an arbitrary point and return a DFS of its dependencies while (_dependenciesByParentObject.Count > 0) { FrugalObjectList <NameFixupToken> startNodeOutEdges = null; foreach (FrugalObjectList <NameFixupToken> list in _dependenciesByParentObject.Values) { startNodeOutEdges = list; break; } for (int i = 0; i < startNodeOutEdges.Count; i++) { List <NameFixupToken> dependencies = new List <NameFixupToken>(); FindDependencies(startNodeOutEdges[i], dependencies); // Iterate the list in backwards order, so we return the deepest first for (int j = dependencies.Count - 1; j >= 0; j--) { NameFixupToken token = dependencies[j]; RemoveTokenByParent(token); yield return(token); } } } // Finally, if there was a deferred ProvideValue at the root, return it if (_deferredRootProvideValue != null) { yield return(_deferredRootProvideValue); } }