protected IDependenciesGraphViewProvider FindViewProvider(IDependency dependency)
 {
     return(_viewProviders.FirstOrDefaultValue((x, d) => x.SupportsDependency(d), dependency));
 }
        /// <summary>
        /// ProjectContextChanged gets fired every time dependencies change for projects across solution.
        /// <see cref="_expandedGraphContexts"/> contains all nodes that we need to check for potential updates
        /// in their child dependencies.
        /// </summary>
        private void OnSnapshotChanged(object sender, SnapshotChangedEventArgs e)
        {
            DependenciesSnapshot snapshot = e.Snapshot;

            if (snapshot == null || e.Token.IsCancellationRequested)
            {
                return;
            }

            // _expandedGraphContexts remembers graph expanded or checked so far.
            // Each context represents one level in the graph, i.e. a node and its first level dependencies
            // Tracking changes over all expanded contexts ensures that all levels are processed
            // and updated when there are any changes in nodes data.
            lock (_lock)
            {
                foreach (IGraphContext graphContext in _expandedGraphContexts)
                {
                    if (e.Token.IsCancellationRequested)
                    {
                        return;
                    }

                    bool anyChanges = false;

                    try
                    {
                        if (HandleChanges(graphContext))
                        {
                            anyChanges = true;
                        }
                    }
                    finally
                    {
                        // Calling OnCompleted ensures that the changes are reflected in UI
                        if (anyChanges)
                        {
                            graphContext.OnCompleted();
                        }
                    }
                }
            }

            return;

            bool HandleChanges(IGraphContext graphContext)
            {
                bool anyChanges = false;

                foreach (GraphNode inputGraphNode in graphContext.InputNodes.ToList())
                {
                    string?existingDependencyId = inputGraphNode.GetValue <string>(DependenciesGraphSchema.DependencyIdProperty);
                    if (string.IsNullOrEmpty(existingDependencyId))
                    {
                        continue;
                    }

                    string?nodeProjectPath = inputGraphNode.Id.GetValue(CodeGraphNodeIdName.Assembly);
                    if (Strings.IsNullOrEmpty(nodeProjectPath))
                    {
                        continue;
                    }

                    DependenciesSnapshot?updatedSnapshot = _aggregateSnapshotProvider.GetSnapshot(nodeProjectPath);

                    IDependency?updatedDependency = updatedSnapshot?.FindDependency(existingDependencyId);

                    if (updatedDependency == null) // or updatedSnapshot == null
                    {
                        continue;
                    }

                    IDependenciesGraphViewProvider?viewProvider = _viewProviders
                                                                  .FirstOrDefaultValue((x, d) => x.SupportsDependency(d), updatedDependency);
                    if (viewProvider == null)
                    {
                        continue;
                    }

                    if (!viewProvider.ShouldApplyChanges(nodeProjectPath, snapshot.ProjectPath, updatedDependency))
                    {
                        continue;
                    }

                    using var scope = new GraphTransactionScope();
                    if (viewProvider.ApplyChanges(
                            graphContext,
                            nodeProjectPath,
                            updatedDependency,
                            inputGraphNode,
                            updatedSnapshot !.DependenciesByTargetFramework[updatedDependency.TargetFramework]))
                    {
                        anyChanges = true;
                    }

                    scope.Complete();
                }

                return(anyChanges);
            }
        }