From 2e3d40a6da9a1daa296a9309f2a15f6f41bcd5a7 Mon Sep 17 00:00:00 2001 From: yotsuda Date: Sat, 6 Dec 2025 00:08:24 +0900 Subject: [PATCH 1/5] Centralize ExcludeProperty filter application in ViewGenerator base class (#26568) --- .../common/FormatViewGenerator.cs | 75 ++++++++++-- .../common/FormatViewGenerator_Complex.cs | 10 +- .../common/FormatViewGenerator_List.cs | 35 ++---- .../common/FormatViewGenerator_Table.cs | 112 +++++++++--------- .../common/FormatViewGenerator_Wide.cs | 84 +++++++------ 5 files changed, 178 insertions(+), 138 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs index cb20e708cc4..ee25131891c 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs @@ -348,19 +348,78 @@ protected class DataBaseInfo protected DataBaseInfo dataBaseInfo = new DataBaseInfo(); - protected List activeAssociationList = null; + private List _activeAssociationList; + + /// + /// Gets the current active association list for read-only access. + /// + protected IReadOnlyList ActiveAssociationList => _activeAssociationList; + + /// + /// Builds the raw association list for the given object. + /// Subclasses override this to provide cmdlet-specific property expansion logic. + /// + /// The object to build the association list for. + /// The raw association list, or null if not applicable. + protected virtual List BuildRawAssociationList(PSObject so) + { + return null; + } + + /// + /// Gets the active association list for the given object, with ExcludeProperty filter applied. + /// If the list is not yet built, it will be built using BuildRawAssociationList. + /// + /// The object to get the association list for. + /// The filtered association list. + protected List GetActiveAssociationList(PSObject so) + { + if (_activeAssociationList is null) + { + var rawList = BuildRawAssociationList(so); + _activeAssociationList = ApplyExcludeFilter(rawList); + } + + return _activeAssociationList; + } + + /// + /// Resets the active association list, forcing it to be rebuilt on next access. + /// + protected void ResetActiveAssociationList() + { + _activeAssociationList = null; + } + /// - /// Apply ExcludeProperty filter to activeAssociationList if specified. - /// This method filters and updates "activeAssociationList" instance property. + /// Applies the ExcludeProperty filter to the given association list. /// - protected void ApplyExcludePropertyFilter() + /// The list to filter. + /// The exclude filter to apply. + /// The filtered list, or the original list if no filter is specified. + internal static List ApplyExcludeFilter( + List associationList, + PSPropertyExpressionFilter excludeFilter) { - if (this.parameters is not null && this.parameters.excludePropertyFilter is not null) + if (associationList is null || excludeFilter is null) { - this.activeAssociationList = this.activeAssociationList - .Where(item => !this.parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression)) - .ToList(); + return associationList; } + + return associationList + .Where(item => !excludeFilter.IsMatch(item.ResolvedExpression)) + .ToList(); + } + + /// + /// Applies the ExcludeProperty filter to the given association list. + /// + /// The list to filter. + /// The filtered list, or the original list if no filter is specified. + private List ApplyExcludeFilter( + List associationList) + { + return ApplyExcludeFilter(associationList, parameters?.excludePropertyFilter); } protected string GetExpressionDisplayValue(PSObject so, int enumerationLimit, PSPropertyExpression ex, diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs index 972a7160830..b81c0c0f860 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Complex.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Collections.ObjectModel; using System.Management.Automation; using System.Management.Automation.Internal; @@ -514,13 +513,8 @@ private void DisplayObject(PSObject so, TraversalInfo currentLevel, List activeAssociationList = AssociationManager.SetupActiveProperties(parameterList, so, _expressionFactory); - // Apply ExcludeProperty filter if specified - if (_parameters != null && _parameters.excludePropertyFilter != null) - { - activeAssociationList = activeAssociationList - .Where(item => !_parameters.excludePropertyFilter.IsMatch(item.ResolvedExpression)) - .ToList(); - } + // Apply ExcludeProperty filter using the centralized method + activeAssociationList = ViewGenerator.ApplyExcludeFilter(activeAssociationList, _parameters?.excludePropertyFilter); // create a format entry FormatEntry fe = new FormatEntry(); diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs index 6ef1b24ce14..c8c1451c62e 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs @@ -30,9 +30,15 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper { _listBody = (ListControlBody)this.dataBaseInfo.view.mainControl; } + } - this.parameters = parameters; - SetUpActiveProperties(so); + /// + /// Builds the raw association list for list formatting. + /// + protected override List BuildRawAssociationList(PSObject so) + { + List mshParameterList = this.parameters?.mshParameterList; + return AssociationManager.SetupActiveProperties(mshParameterList, so, this.expressionFactory); } /// @@ -178,17 +184,14 @@ private ListControlEntryDefinition GetActiveListControlEntryDefinition(ListContr private ListViewEntry GenerateListViewEntryFromProperties(PSObject so, int enumerationLimit) { - // compute active properties every time - if (this.activeAssociationList == null) - { - SetUpActiveProperties(so); - } + // Get active association list (with ExcludeProperty filter applied) + var associationList = GetActiveAssociationList(so); ListViewEntry lve = new ListViewEntry(); - for (int k = 0; k < this.activeAssociationList.Count; k++) + for (int k = 0; k < associationList.Count; k++) { - MshResolvedExpressionParameterAssociation a = this.activeAssociationList[k]; + MshResolvedExpressionParameterAssociation a = associationList[k]; ListViewField lvf = new ListViewField(); if (a.OriginatingParameter != null) @@ -219,20 +222,8 @@ private ListViewEntry GenerateListViewEntryFromProperties(PSObject so, int enume lve.listViewFieldList.Add(lvf); } - this.activeAssociationList = null; + ResetActiveAssociationList(); return lve; } - - private void SetUpActiveProperties(PSObject so) - { - List mshParameterList = null; - - if (this.parameters != null) - mshParameterList = this.parameters.mshParameterList; - - this.activeAssociationList = AssociationManager.SetupActiveProperties(mshParameterList, so, this.expressionFactory); - - ApplyExcludePropertyFilter(); - } } } diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index 33d2bd53506..cf77e94dfa3 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -34,51 +34,50 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper _tableBody = (TableControlBody)this.dataBaseInfo.view.mainControl; } - List rawMshParameterList = null; + // Build the active association list (with ExcludeProperty filter applied) + _ = GetActiveAssociationList(so); + } - if (parameters != null) - rawMshParameterList = parameters.mshParameterList; + /// + /// Builds the raw association list for table formatting. + /// + protected override List BuildRawAssociationList(PSObject so) + { + List rawMshParameterList = this.parameters?.mshParameterList; // check if we received properties from the command line if (rawMshParameterList is not null && rawMshParameterList.Count > 0) { - this.activeAssociationList = AssociationManager.ExpandTableParameters(rawMshParameterList, so); + return AssociationManager.ExpandTableParameters(rawMshParameterList, so); } - else + + // we did not get any properties: + // try to get properties from the default property set of the object + var list = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); + if (list.Count > 0) { - // we did not get any properties: - // try to get properties from the default property set of the object - this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); - if (this.activeAssociationList.Count > 0) + // we got a valid set of properties from the default property set..add computername for + // remoteobjects (if available) + if (PSObjectHelper.ShouldShowComputerNameProperty(so)) { - // we got a valid set of properties from the default property set..add computername for - // remoteobjects (if available) - if (PSObjectHelper.ShouldShowComputerNameProperty(so)) - { - activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, - new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty))); - } - } - else - { - // we failed to get anything from the default property set - this.activeAssociationList = AssociationManager.ExpandAll(so); - if (this.activeAssociationList.Count > 0) - { - // Remove PSComputerName and PSShowComputerName from the display as needed. - AssociationManager.HandleComputerNameProperties(so, activeAssociationList); - FilterActiveAssociationList(); - } - else - { - // we were unable to retrieve any properties, so we leave an empty list - this.activeAssociationList = new List(); - return; - } + list.Add(new MshResolvedExpressionParameterAssociation(null, + new PSPropertyExpression(RemotingConstants.ComputerNameNoteProperty))); } + + return list; + } + + // we failed to get anything from the default property set + list = AssociationManager.ExpandAll(so); + if (list.Count > 0) + { + // Remove PSComputerName and PSShowComputerName from the display as needed. + AssociationManager.HandleComputerNameProperties(so, list); + return LimitAssociationListSize(list); } - ApplyExcludePropertyFilter(); + // we were unable to retrieve any properties, so we leave an empty list + return new List(); } /// @@ -129,30 +128,29 @@ internal override FormatStartData GenerateStartData(PSObject so) } /// - /// Method to filter resolved expressions as per table view needs. + /// Limits the association list size for table view. /// For v1.0, table view supports only 10 properties. - /// - /// This method filters and updates "activeAssociationList" instance property. /// - /// None. - /// This method updates "activeAssociationList" instance property. - private void FilterActiveAssociationList() + /// The list to limit. + /// The limited list. + private static List LimitAssociationListSize( + List list) { - // we got a valid set of properties from the default property set - // make sure we do not have too many properties - // NOTE: this is an arbitrary number, chosen to be a sensitive default - const int nMax = 10; + const int maxCount = 10; + + if (list.Count <= maxCount) + { + return list; + } - if (activeAssociationList.Count > nMax) + var result = new List(maxCount); + for (int k = 0; k < maxCount; k++) { - List tmp = this.activeAssociationList; - this.activeAssociationList = new List(); - for (int k = 0; k < nMax; k++) - this.activeAssociationList.Add(tmp[k]); + result.Add(list[k]); } - return; + return result; } private TableHeaderInfo GenerateTableHeaderInfoFromDataBaseInfo(PSObject so) @@ -228,9 +226,9 @@ private TableHeaderInfo GenerateTableHeaderInfoFromProperties(PSObject so) thi.hideHeader = this.HideHeaders; thi.repeatHeader = this.RepeatHeader; - for (int k = 0; k < this.activeAssociationList.Count; k++) + for (int k = 0; k < this.ActiveAssociationList.Count; k++) { - MshResolvedExpressionParameterAssociation a = this.activeAssociationList[k]; + MshResolvedExpressionParameterAssociation a = this.ActiveAssociationList[k]; TableColumnInfo ci = new TableColumnInfo(); // set the label of the column @@ -241,7 +239,7 @@ private TableHeaderInfo GenerateTableHeaderInfoFromProperties(PSObject so) ci.propertyName = (string)key; } - ci.propertyName ??= this.activeAssociationList[k].ResolvedExpression.ToString(); + ci.propertyName ??= this.ActiveAssociationList[k].ResolvedExpression.ToString(); // set the width of the table if (a.OriginatingParameter != null) @@ -473,13 +471,13 @@ private TableRowEntry GenerateTableRowEntryFromDataBaseInfo(PSObject so, int enu private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int enumerationLimit) { TableRowEntry tre = new TableRowEntry(); - for (int k = 0; k < this.activeAssociationList.Count; k++) + for (int k = 0; k < this.ActiveAssociationList.Count; k++) { FormatPropertyField fpf = new FormatPropertyField(); FieldFormattingDirective directive = null; - if (activeAssociationList[k].OriginatingParameter != null) + if (ActiveAssociationList[k].OriginatingParameter != null) { - directive = activeAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective; + directive = ActiveAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective; } if (directive is null) @@ -488,7 +486,7 @@ private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int e directive.isTable = true; } - fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, this.activeAssociationList[k].ResolvedExpression, directive); + fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, this.ActiveAssociationList[k].ResolvedExpression, directive); tre.formatPropertyFieldList.Add(fpf); } diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs index a45c006e7fc..f903cf4fbe9 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs @@ -15,6 +15,42 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper base.Initialize(errorContext, expressionFactory, so, db, parameters); } + /// + /// Builds the raw association list for wide formatting. + /// + protected override List BuildRawAssociationList(PSObject so) + { + List rawMshParameterList = this.parameters?.mshParameterList; + + // check if we received properties from the command line + if (rawMshParameterList is not null && rawMshParameterList.Count > 0) + { + return AssociationManager.ExpandParameters(rawMshParameterList, so); + } + + // we did not get any properties: + // try to get the display property of the object + PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory); + if (displayNameExpression is not null) + { + return new List + { + new MshResolvedExpressionParameterAssociation(null, displayNameExpression) + }; + } + + // try to get the default property set (we will use the first property) + var list = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); + if (list.Count == 0) + { + // we failed to get anything from the default property set + // just get all the properties + list = AssociationManager.ExpandAll(so); + } + + return list; + } + internal override FormatStartData GenerateStartData(PSObject so) { FormatStartData startFormat = base.GenerateStartData(so); @@ -129,20 +165,17 @@ private WideControlEntryDefinition GetActiveWideControlEntryDefinition(WideContr private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enumerationLimit) { - // compute active properties every time - if (this.activeAssociationList == null) - { - SetUpActiveProperty(so); - } + // Get active association list (with ExcludeProperty filter applied) + var associationList = GetActiveAssociationList(so); WideViewEntry wve = new WideViewEntry(); FormatPropertyField fpf = new FormatPropertyField(); wve.formatPropertyField = fpf; - if (this.activeAssociationList.Count > 0) + if (associationList.Count > 0) { // get the first one - MshResolvedExpressionParameterAssociation a = this.activeAssociationList[0]; + MshResolvedExpressionParameterAssociation a = associationList[0]; FieldFormattingDirective directive = null; if (a.OriginatingParameter != null) { @@ -152,43 +185,8 @@ private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enume fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, a.ResolvedExpression, directive); } - this.activeAssociationList = null; + ResetActiveAssociationList(); return wve; } - - private void SetUpActiveProperty(PSObject so) - { - List rawMshParameterList = this.parameters?.mshParameterList; - - // check if we received properties from the command line - if (rawMshParameterList is not null && rawMshParameterList.Count > 0) - { - this.activeAssociationList = AssociationManager.ExpandParameters(rawMshParameterList, so); - } - else - { - // we did not get any properties: - // try to get the display property of the object - PSPropertyExpression displayNameExpression = PSObjectHelper.GetDisplayNameExpression(so, this.expressionFactory); - if (displayNameExpression is not null) - { - this.activeAssociationList = new List(); - this.activeAssociationList.Add(new MshResolvedExpressionParameterAssociation(null, displayNameExpression)); - } - else - { - // try to get the default property set (we will use the first property) - this.activeAssociationList = AssociationManager.ExpandDefaultPropertySet(so, this.expressionFactory); - if (this.activeAssociationList.Count == 0) - { - // we failed to get anything from the default property set - // just get all the properties - this.activeAssociationList = AssociationManager.ExpandAll(so); - } - } - } - - ApplyExcludePropertyFilter(); - } } } From 63e05d9d25a698a1175d8af822b0428e27f0533b Mon Sep 17 00:00:00 2001 From: yotsuda Date: Sat, 6 Dec 2025 08:04:54 +0900 Subject: [PATCH 2/5] Refactor to pass propertyList and excludeFilter as explicit method parameters --- .../common/FormatViewGenerator.cs | 20 ++++++------------- .../common/FormatViewGenerator_List.cs | 5 ++--- .../common/FormatViewGenerator_Table.cs | 8 +++----- .../common/FormatViewGenerator_Wide.cs | 8 +++----- 4 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs index ee25131891c..93e2c0e6f8a 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs @@ -360,8 +360,9 @@ protected class DataBaseInfo /// Subclasses override this to provide cmdlet-specific property expansion logic. /// /// The object to build the association list for. + /// The list of properties specified by the user, or null if not specified. /// The raw association list, or null if not applicable. - protected virtual List BuildRawAssociationList(PSObject so) + protected virtual List BuildRawAssociationList(PSObject so, List propertyList) { return null; } @@ -376,8 +377,10 @@ protected List GetActiveAssociationLi { if (_activeAssociationList is null) { - var rawList = BuildRawAssociationList(so); - _activeAssociationList = ApplyExcludeFilter(rawList); + var propertyList = parameters?.mshParameterList; + var excludeFilter = parameters?.excludePropertyFilter; + var rawList = BuildRawAssociationList(so, propertyList); + _activeAssociationList = ApplyExcludeFilter(rawList, excludeFilter); } return _activeAssociationList; @@ -411,17 +414,6 @@ internal static List ApplyExcludeFilt .ToList(); } - /// - /// Applies the ExcludeProperty filter to the given association list. - /// - /// The list to filter. - /// The filtered list, or the original list if no filter is specified. - private List ApplyExcludeFilter( - List associationList) - { - return ApplyExcludeFilter(associationList, parameters?.excludePropertyFilter); - } - protected string GetExpressionDisplayValue(PSObject so, int enumerationLimit, PSPropertyExpression ex, FieldFormattingDirective directive) { diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs index c8c1451c62e..ab4e3528217 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs @@ -35,10 +35,9 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper /// /// Builds the raw association list for list formatting. /// - protected override List BuildRawAssociationList(PSObject so) + protected override List BuildRawAssociationList(PSObject so, List propertyList) { - List mshParameterList = this.parameters?.mshParameterList; - return AssociationManager.SetupActiveProperties(mshParameterList, so, this.expressionFactory); + return AssociationManager.SetupActiveProperties(propertyList, so, this.expressionFactory); } /// diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index cf77e94dfa3..f508163c1cd 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -41,14 +41,12 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper /// /// Builds the raw association list for table formatting. /// - protected override List BuildRawAssociationList(PSObject so) + protected override List BuildRawAssociationList(PSObject so, List propertyList) { - List rawMshParameterList = this.parameters?.mshParameterList; - // check if we received properties from the command line - if (rawMshParameterList is not null && rawMshParameterList.Count > 0) + if (propertyList is not null && propertyList.Count > 0) { - return AssociationManager.ExpandTableParameters(rawMshParameterList, so); + return AssociationManager.ExpandTableParameters(propertyList, so); } // we did not get any properties: diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs index f903cf4fbe9..6414c398461 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs @@ -18,14 +18,12 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper /// /// Builds the raw association list for wide formatting. /// - protected override List BuildRawAssociationList(PSObject so) + protected override List BuildRawAssociationList(PSObject so, List propertyList) { - List rawMshParameterList = this.parameters?.mshParameterList; - // check if we received properties from the command line - if (rawMshParameterList is not null && rawMshParameterList.Count > 0) + if (propertyList is not null && propertyList.Count > 0) { - return AssociationManager.ExpandParameters(rawMshParameterList, so); + return AssociationManager.ExpandParameters(propertyList, so); } // we did not get any properties: From 0e53e55ca04286df807b3ef8e207ad25581d715d Mon Sep 17 00:00:00 2001 From: yotsuda Date: Sat, 6 Dec 2025 16:29:12 +0900 Subject: [PATCH 3/5] Change ActiveAssociationList property type from IReadOnlyList to List --- .../FormatAndOutput/common/FormatViewGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs index 93e2c0e6f8a..2194a451fb8 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs @@ -351,9 +351,9 @@ protected class DataBaseInfo private List _activeAssociationList; /// - /// Gets the current active association list for read-only access. + /// Gets the current active association list. /// - protected IReadOnlyList ActiveAssociationList => _activeAssociationList; + protected List ActiveAssociationList => _activeAssociationList; /// /// Builds the raw association list for the given object. From ca1825636196fb137eba46f0e527b0eb55be7c2a Mon Sep 17 00:00:00 2001 From: yotsuda Date: Mon, 8 Dec 2025 14:33:24 +0900 Subject: [PATCH 4/5] Refactor BuildActiveAssociationList to remove misleading caching from base class --- .../common/FormatViewGenerator.cs | 35 ++++--------------- .../common/FormatViewGenerator_List.cs | 6 ++-- .../common/FormatViewGenerator_Table.cs | 9 ++++- .../common/FormatViewGenerator_Wide.cs | 6 ++-- 4 files changed, 19 insertions(+), 37 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs index 2194a451fb8..963b5a0f88b 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator.cs @@ -348,13 +348,6 @@ protected class DataBaseInfo protected DataBaseInfo dataBaseInfo = new DataBaseInfo(); - private List _activeAssociationList; - - /// - /// Gets the current active association list. - /// - protected List ActiveAssociationList => _activeAssociationList; - /// /// Builds the raw association list for the given object. /// Subclasses override this to provide cmdlet-specific property expansion logic. @@ -368,30 +361,16 @@ protected virtual List BuildRawAssoci } /// - /// Gets the active association list for the given object, with ExcludeProperty filter applied. - /// If the list is not yet built, it will be built using BuildRawAssociationList. + /// Builds the active association list for the given object, with ExcludeProperty filter applied. /// - /// The object to get the association list for. + /// The object to build the association list for. /// The filtered association list. - protected List GetActiveAssociationList(PSObject so) - { - if (_activeAssociationList is null) - { - var propertyList = parameters?.mshParameterList; - var excludeFilter = parameters?.excludePropertyFilter; - var rawList = BuildRawAssociationList(so, propertyList); - _activeAssociationList = ApplyExcludeFilter(rawList, excludeFilter); - } - - return _activeAssociationList; - } - - /// - /// Resets the active association list, forcing it to be rebuilt on next access. - /// - protected void ResetActiveAssociationList() + protected List BuildActiveAssociationList(PSObject so) { - _activeAssociationList = null; + var propertyList = parameters?.mshParameterList; + var excludeFilter = parameters?.excludePropertyFilter; + var rawList = BuildRawAssociationList(so, propertyList); + return ApplyExcludeFilter(rawList, excludeFilter); } /// diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs index ab4e3528217..35287d7c2e4 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_List.cs @@ -183,8 +183,8 @@ private ListControlEntryDefinition GetActiveListControlEntryDefinition(ListContr private ListViewEntry GenerateListViewEntryFromProperties(PSObject so, int enumerationLimit) { - // Get active association list (with ExcludeProperty filter applied) - var associationList = GetActiveAssociationList(so); + // Build active association list (with ExcludeProperty filter applied) + var associationList = BuildActiveAssociationList(so); ListViewEntry lve = new ListViewEntry(); @@ -220,8 +220,6 @@ private ListViewEntry GenerateListViewEntryFromProperties(PSObject so, int enume lvf.formatPropertyField.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, a.ResolvedExpression, directive); lve.listViewFieldList.Add(lvf); } - - ResetActiveAssociationList(); return lve; } } diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index f508163c1cd..bb4bb03f78f 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -14,6 +14,13 @@ internal sealed class TableViewGenerator : ViewGenerator // tableBody to use for this instance of the ViewGenerator; private TableControlBody _tableBody; + private List _activeAssociationList; + + /// + /// Gets the cached active association list. + /// + private List ActiveAssociationList => _activeAssociationList; + internal override void Initialize(TerminatingErrorContext terminatingErrorContext, PSPropertyExpressionFactory mshExpressionFactory, TypeInfoDataBase db, ViewDefinition view, FormattingCommandLineParameters formatParameters) { base.Initialize(terminatingErrorContext, mshExpressionFactory, db, view, formatParameters); @@ -35,7 +42,7 @@ internal override void Initialize(TerminatingErrorContext errorContext, PSProper } // Build the active association list (with ExcludeProperty filter applied) - _ = GetActiveAssociationList(so); + _activeAssociationList = BuildActiveAssociationList(so); } /// diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs index 6414c398461..bfa364cc450 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Wide.cs @@ -163,8 +163,8 @@ private WideControlEntryDefinition GetActiveWideControlEntryDefinition(WideContr private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enumerationLimit) { - // Get active association list (with ExcludeProperty filter applied) - var associationList = GetActiveAssociationList(so); + // Build active association list (with ExcludeProperty filter applied) + var associationList = BuildActiveAssociationList(so); WideViewEntry wve = new WideViewEntry(); FormatPropertyField fpf = new FormatPropertyField(); @@ -182,8 +182,6 @@ private WideViewEntry GenerateWideViewEntryFromProperties(PSObject so, int enume fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, a.ResolvedExpression, directive); } - - ResetActiveAssociationList(); return wve; } } From 569f6004d2b3ae4cdc1951aef33b85698aa69f96 Mon Sep 17 00:00:00 2001 From: yotsuda Date: Wed, 10 Dec 2025 10:15:02 +0900 Subject: [PATCH 5/5] Remove redundant ActiveAssociationList property and access field directly --- .../common/FormatViewGenerator_Table.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index bb4bb03f78f..3b14c0754ba 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -16,11 +16,6 @@ internal sealed class TableViewGenerator : ViewGenerator private List _activeAssociationList; - /// - /// Gets the cached active association list. - /// - private List ActiveAssociationList => _activeAssociationList; - internal override void Initialize(TerminatingErrorContext terminatingErrorContext, PSPropertyExpressionFactory mshExpressionFactory, TypeInfoDataBase db, ViewDefinition view, FormattingCommandLineParameters formatParameters) { base.Initialize(terminatingErrorContext, mshExpressionFactory, db, view, formatParameters); @@ -231,9 +226,9 @@ private TableHeaderInfo GenerateTableHeaderInfoFromProperties(PSObject so) thi.hideHeader = this.HideHeaders; thi.repeatHeader = this.RepeatHeader; - for (int k = 0; k < this.ActiveAssociationList.Count; k++) + for (int k = 0; k < _activeAssociationList.Count; k++) { - MshResolvedExpressionParameterAssociation a = this.ActiveAssociationList[k]; + MshResolvedExpressionParameterAssociation a = _activeAssociationList[k]; TableColumnInfo ci = new TableColumnInfo(); // set the label of the column @@ -244,7 +239,7 @@ private TableHeaderInfo GenerateTableHeaderInfoFromProperties(PSObject so) ci.propertyName = (string)key; } - ci.propertyName ??= this.ActiveAssociationList[k].ResolvedExpression.ToString(); + ci.propertyName ??= _activeAssociationList[k].ResolvedExpression.ToString(); // set the width of the table if (a.OriginatingParameter != null) @@ -476,13 +471,13 @@ private TableRowEntry GenerateTableRowEntryFromDataBaseInfo(PSObject so, int enu private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int enumerationLimit) { TableRowEntry tre = new TableRowEntry(); - for (int k = 0; k < this.ActiveAssociationList.Count; k++) + for (int k = 0; k < _activeAssociationList.Count; k++) { FormatPropertyField fpf = new FormatPropertyField(); FieldFormattingDirective directive = null; - if (ActiveAssociationList[k].OriginatingParameter != null) + if (_activeAssociationList[k].OriginatingParameter != null) { - directive = ActiveAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective; + directive = _activeAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective; } if (directive is null) @@ -491,7 +486,7 @@ private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int e directive.isTable = true; } - fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, this.ActiveAssociationList[k].ResolvedExpression, directive); + fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, _activeAssociationList[k].ResolvedExpression, directive); tre.formatPropertyFieldList.Add(fpf); }