Skip to content

fix: share ProjectCollection instance and implement IDisposable - #69

Closed
mfogliatto wants to merge 1 commit into
mainfrom
fix/issue-68
Closed

fix: share ProjectCollection instance and implement IDisposable#69
mfogliatto wants to merge 1 commit into
mainfrom
fix/issue-68

Conversation

@mfogliatto

Copy link
Copy Markdown
Owner

Summary

Fixes #68 — eliminates redundant ProjectCollection instances and project loads, and properly disposes the IDisposable resource.

Problem

MSBuildProjectMetadataProvider was creating a new ProjectCollection and calling LoadProject() in both GetProjectReferences() and GetPropertyValue(). Since ReferenceCopTask.Execute() calls both methods for the same project file, this caused:

  1. Double project evaluation — full MSBuild project parsing (XML, properties, imports) happening twice per task invocation
  2. Resource leakProjectCollection implements IDisposable but was never disposed, leaking unmanaged resources (COM interop, file handles)
  3. Build-time cost — compounds across a solution: 2N unnecessary evaluations for N projects

Changes

MSBuildProjectMetadataProvider.cs

  • Now holds a single shared ProjectCollection created in the constructor
  • Added LoadOrGetProject() helper that checks ProjectCollection.GetLoadedProjects() before loading, so the project is only parsed once even when both methods are called
  • Implements IDisposable with proper dispose pattern (UnloadAllProjects() + Dispose() on the collection)

ReferenceCopTask.cs

  • Execute() now disposes the provider in a finally block via safe cast: (this.projectReferencesProvider as IDisposable)?.Dispose()
  • Safe for test scenarios where mocked providers don't implement IDisposable

Impact

  • 50% reduction in MSBuild project evaluations per task invocation
  • No more resource leaks from undisposed ProjectCollection instances
  • Backward compatible — no interface changes, no new dependencies

Refactor MSBuildProjectMetadataProvider to use a single ProjectCollection
instance across both GetProjectReferences() and GetPropertyValue(),
eliminating redundant project loads when both methods are called for the
same project file.

Changes:
- MSBuildProjectMetadataProvider now holds a shared ProjectCollection
  created once in the constructor
- Added LoadOrGetProject() helper that caches loaded projects via
  ProjectCollection.GetLoadedProjects(), avoiding double evaluation
- Implemented IDisposable with proper dispose pattern to clean up the
  ProjectCollection (UnloadAllProjects + Dispose)
- ReferenceCopTask.Execute() now disposes the provider in a finally
  block using safe cast (as IDisposable)?.Dispose()

Fixes #68
@mfogliatto mfogliatto closed this Jun 7, 2026
@mfogliatto
mfogliatto deleted the fix/issue-68 branch June 13, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Performance] MSBuildProjectMetadataProvider creates redundant ProjectCollection instances and leaks IDisposable

1 participant