Skip to content

Commit 6b4f781

Browse files
authored
Merge pull request #9686 from drewnoakes/fix-2707-dep-tree-perf
Improve perf of accessing configured values in tree, particularly during solution load
2 parents 80f889a + dfdc9d7 commit 6b4f781

File tree

2 files changed

+32
-28
lines changed

2 files changed

+32
-28
lines changed

src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/Dependencies/DependenciesTreeProvider.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ internal sealed partial class DependenciesTreeProvider : ProjectTreeProviderBase
4747
private readonly OrderPrecedenceImportCollection<IProjectTreeActionHandler> _removalActionHandlers;
4848

4949
private readonly DependenciesSnapshotProvider _dependenciesSnapshotProvider;
50+
private readonly IActiveConfiguredValue<IConfiguredProjectExports> _activeConfiguredProjectExports;
5051
private readonly CancellationSeries _treeUpdateCancellationSeries;
5152
private readonly IProjectAccessor _projectAccessor;
52-
private readonly ITaskDelayScheduler _debounce;
53+
private readonly TaskDelayScheduler _debounce;
5354

55+
// NOTE we use a property import here as importing this via the constructor creates a loop between
56+
// DependenciesTreeProvider and DependenciesTreeBuilder. A property import allows MEF to break that
57+
// circular dependency.
5458
[Import]
5559
private DependenciesTreeBuilder TreeBuilder { get; set; } = null!;
5660

@@ -68,11 +72,13 @@ public DependenciesTreeProvider(
6872
IProjectThreadingService threadingService,
6973
IUnconfiguredProjectTasksService tasksService,
7074
IProjectAccessor projectAccessor,
71-
DependenciesSnapshotProvider dependenciesSnapshotProvider)
75+
DependenciesSnapshotProvider dependenciesSnapshotProvider,
76+
IActiveConfiguredValue<IConfiguredProjectExports> activeConfiguredProjectExports)
7277
: base(threadingService, unconfiguredProject)
7378
{
7479
_dependenciesSnapshotProvider = dependenciesSnapshotProvider;
7580
_projectAccessor = projectAccessor;
81+
_activeConfiguredProjectExports = activeConfiguredProjectExports;
7682

7783
_removalActionHandlers = new OrderPrecedenceImportCollection<IProjectTreeActionHandler>(
7884
ImportOrderPrecedenceComparer.PreferenceOrder.PreferredComesFirst,
@@ -377,7 +383,7 @@ await _projectAccessor.OpenProjectForWriteAsync(ActiveConfiguredProject, project
377383

378384
protected override ConfiguredProjectExports GetActiveConfiguredProjectExports(ConfiguredProject newActiveConfiguredProject)
379385
{
380-
return GetActiveConfiguredProjectExports<MyConfiguredProjectExports>(newActiveConfiguredProject);
386+
return (ConfiguredProjectExports)_activeConfiguredProjectExports.Value;
381387
}
382388

383389
#region ITreeConstruction
@@ -479,29 +485,25 @@ IProjectItemTree2 IProjectTreeOperations.NewTree(string caption, IProjectPropert
479485
/// <summary>
480486
/// Describes services collected from the active configured project.
481487
/// </summary>
482-
[Export]
483-
private sealed class MyConfiguredProjectExports : ConfiguredProjectExports
488+
[Export(typeof(IConfiguredProjectExports))]
489+
[method: ImportingConstructor]
490+
private sealed class MyConfiguredProjectExports(ConfiguredProject configuredProject)
491+
: ConfiguredProjectExports(configuredProject),
492+
IConfiguredProjectExports
484493
{
485-
[ImportingConstructor]
486-
public MyConfiguredProjectExports(ConfiguredProject configuredProject)
487-
: base(configuredProject)
488-
{
489-
}
490494
}
491495

492496
/// <summary>
493497
/// A private implementation of <see cref="IProjectTreeActionHandlerContext"/> for use with
494498
/// <see cref="IProjectTreeActionHandler"/> exports.
495499
/// </summary>
496-
private sealed class ProjectDependencyTreeRemovalActionHandlerContext : IProjectTreeActionHandlerContext
500+
private sealed class ProjectDependencyTreeRemovalActionHandlerContext(IProjectTreeProvider treeProvider) : IProjectTreeActionHandlerContext
497501
{
498-
public IProjectTreeProvider TreeProvider { get; }
502+
public IProjectTreeProvider TreeProvider { get; } = treeProvider;
499503

500504
public IProjectTreeActionHandler SuccessorHandlerDelegator => throw new NotImplementedException();
501-
502-
public ProjectDependencyTreeRemovalActionHandlerContext(IProjectTreeProvider treeProvider)
503-
{
504-
TreeProvider = treeProvider;
505-
}
506505
}
506+
507+
// NOTE this interface is needed to work around accessiblity issues when making MyConfiguredProjectExports non-private
508+
internal interface IConfiguredProjectExports { }
507509
}

src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Tree/ProjectImports/ImportTreeProvider.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ internal sealed class ImportTreeProvider : ProjectTreeProviderBase, IProjectTree
4545
private readonly UnconfiguredProject _project;
4646
private readonly IActiveConfiguredProjectSubscriptionService _projectSubscriptionService;
4747
private readonly IUnconfiguredProjectTasksService _unconfiguredProjectTasksService;
48+
private readonly IActiveConfiguredValue<IConfiguredProjectExports> _activeConfiguredProjectExports;
4849

4950
private DisposableBag? _subscriptions;
5051
private bool _showAllFiles;
@@ -54,12 +55,14 @@ internal ImportTreeProvider(
5455
IProjectThreadingService threadingService,
5556
UnconfiguredProject project,
5657
IActiveConfiguredProjectSubscriptionService projectSubscriptionService,
57-
IUnconfiguredProjectTasksService unconfiguredProjectTasksService)
58+
IUnconfiguredProjectTasksService unconfiguredProjectTasksService,
59+
IActiveConfiguredValue<IConfiguredProjectExports> activeConfiguredProjectExports)
5860
: base(threadingService, project, useDisplayOrdering: true)
5961
{
6062
_project = project;
6163
_projectSubscriptionService = projectSubscriptionService;
6264
_unconfiguredProjectTasksService = unconfiguredProjectTasksService;
65+
_activeConfiguredProjectExports = activeConfiguredProjectExports;
6366
}
6467

6568
public override string? GetPath(IProjectTree node)
@@ -346,9 +349,7 @@ void TearDownTree()
346349

347350
protected override ConfiguredProjectExports GetActiveConfiguredProjectExports(ConfiguredProject newActiveConfiguredProject)
348351
{
349-
Requires.NotNull(newActiveConfiguredProject);
350-
351-
return GetActiveConfiguredProjectExports<MyConfiguredProjectExports>(newActiveConfiguredProject);
352+
return (ConfiguredProjectExports)_activeConfiguredProjectExports.Value;
352353
}
353354

354355
protected override void Dispose(bool disposing)
@@ -361,13 +362,14 @@ protected override void Dispose(bool disposing)
361362
base.Dispose(disposing);
362363
}
363364

364-
[Export]
365-
private sealed class MyConfiguredProjectExports : ConfiguredProjectExports
365+
[Export(typeof(IConfiguredProjectExports))]
366+
[method: ImportingConstructor]
367+
private sealed class MyConfiguredProjectExports(ConfiguredProject configuredProject)
368+
: ConfiguredProjectExports(configuredProject),
369+
IConfiguredProjectExports
366370
{
367-
[ImportingConstructor]
368-
public MyConfiguredProjectExports(ConfiguredProject configuredProject)
369-
: base(configuredProject)
370-
{
371-
}
372371
}
372+
373+
// NOTE this interface is needed to work around accessiblity issues when making MyConfiguredProjectExports non-private
374+
internal interface IConfiguredProjectExports { }
373375
}

0 commit comments

Comments
 (0)