| File: Evaluation\ProjectRootElementCacheBase.cs | Web Access |
| Project: src\msbuild\src\Build\Microsoft.Build.csproj (Microsoft.Build) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.Build.Construction; #nullable disable namespace Microsoft.Build.Evaluation { internal abstract class ProjectRootElementCacheBase { public bool LoadProjectsReadOnly { get; protected set; } public ParserIgnoreConfiguration ParserIgnoreConfiguration { get; protected set; } /// <summary> /// Whether <see cref="SetParserIgnoreConfiguration"/> has already been applied to this cache. A null /// <see cref="ParserIgnoreConfiguration"/> is a legitimate configuration - it is what the escape hatch /// produces - so it cannot itself stand for "never set". /// </summary> private bool _parserIgnoreConfigurationInitialized; /// <summary> /// Handler for which project root element just got added to the cache /// </summary> internal delegate void ProjectRootElementCacheAddEntryHandler(object sender, ProjectRootElementCacheAddEntryEventArgs e); /// <summary> /// Delegate for StrongCacheEntryRemoved event /// </summary> internal delegate void StrongCacheEntryRemovedDelegate(object sender, ProjectRootElement projectRootElement); /// <summary> /// Callback to create a ProjectRootElement if need be /// </summary> internal delegate ProjectRootElement OpenProjectRootElement(string path, ProjectRootElementCacheBase cache); /// <summary> /// Event which is fired when a project root element is added to this cache. /// </summary> internal event ProjectRootElementCacheAddEntryHandler ProjectRootElementAddedHandler; /// <summary> /// Event which is fired when a project root element in this cache is dirtied. /// </summary> internal event EventHandler<ProjectXmlChangedEventArgs> ProjectRootElementDirtied; /// <summary> /// Event which is fired when a project is marked dirty. /// </summary> internal event EventHandler<ProjectChangedEventArgs> ProjectDirtied; internal abstract ProjectRootElement Get(string projectFile, OpenProjectRootElement loadProjectRootElement, bool isExplicitlyLoaded, bool? preserveFormatting); internal abstract void AddEntry(ProjectRootElement projectRootElement); internal abstract void RenameEntry(string oldFullPath, ProjectRootElement projectRootElement); internal abstract ProjectRootElement TryGet(string projectFile); internal abstract ProjectRootElement TryGet(string projectFile, bool? preserveFormatting); internal abstract void DiscardStrongReferences(); internal abstract void Clear(); /// <summary> /// Called when the host has determined that something outside the build - typically restore - may have /// rewritten part of the import graph, and the cache must not go on serving what it read before that. /// Discarding everything always satisfies that; a cache that can tell on its own which of its entries a /// rewrite invalidated may override this to discard only those. /// </summary> internal virtual void ClearCachesAfterBuildIfNeeded() => Clear(); internal abstract void DiscardImplicitReferences(); internal abstract void DiscardAnyWeakReference(ProjectRootElement projectRootElement); internal void SetParserIgnoreConfiguration(ParserIgnoreConfiguration configuration) { if (ParserIgnoreConfiguration.Equals(ParserIgnoreConfiguration, configuration)) { return; } // Entries parsed under the previous configuration may have skipped - or refused to skip - unknown // attributes and elements that the new one treats differently, so they must be reparsed. A cache that // has not had a configuration applied yet holds nothing parsed under a different one, so on that first // initialization - which happens once per newly created cache - there is nothing to invalidate. if (_parserIgnoreConfigurationInitialized) { DiscardImplicitReferences(); } _parserIgnoreConfigurationInitialized = true; ParserIgnoreConfiguration = configuration; } /// <summary> /// Raises the <see cref="ProjectRootElementDirtied"/> event. /// </summary> /// <param name="sender">The dirtied project root element.</param> /// <param name="e">Details on the PRE and the nature of the change.</param> internal virtual void OnProjectRootElementDirtied(ProjectRootElement sender, ProjectXmlChangedEventArgs e) { var cacheDirtied = ProjectRootElementDirtied; cacheDirtied?.Invoke(sender, e); } /// <summary> /// Raises the <see cref="ProjectDirtied"/> event. /// </summary> /// <param name="sender">The dirtied project.</param> /// <param name="e">Details on the Project and the change.</param> internal virtual void OnProjectDirtied(Project sender, ProjectChangedEventArgs e) { var projectDirtied = ProjectDirtied; projectDirtied?.Invoke(sender, e); } /// <summary> /// Raises an event which is raised when a project root element is added to the cache. /// </summary> protected void RaiseProjectRootElementAddedToCacheEvent(ProjectRootElement rootElement) { ProjectRootElementAddedHandler?.Invoke(this, new ProjectRootElementCacheAddEntryEventArgs(rootElement)); } } /// <summary> /// This class is an event that holds which ProjectRootElement was added to the root element cache. /// </summary> internal class ProjectRootElementCacheAddEntryEventArgs : EventArgs { /// <summary> /// Takes the root element which was added to the results cache. /// </summary> internal ProjectRootElementCacheAddEntryEventArgs(ProjectRootElement element) { RootElement = element; } /// <summary> /// Root element which was just added to the cache. /// </summary> internal readonly ProjectRootElement RootElement; } }