Skip to content

Commit 4f2a020

Browse files
dfedermrainersigwald
authored andcommitted
Avoid boxing when enumerating project xml children
In a recent profile of a graph construction, it was observed that a large amount of boxing was happening for ProjectElementSiblingEnumerable. This change simplifies how xml children are enumerated by adding an internal ChildrenEnumerable property which directly exposes the ProjectElementSiblingEnumerable which should avoid boxing, at least in some code paths (the public API makes it hard to avoid everywhere...). Additionally, a very common usage of enumerating children was to do Children.OfType<T> and wrap it in a ReadOnlyCollection<T>, so I introduced a GetChildrenOfType (and GetChildrenReversedOfType) method which exposes an ICollection<T> which does the same thing but without the boxing of ProjectElementSiblingEnumerable and without the OfType class. It's just 1 collection allocation.
1 parent 5785ed5 commit 4f2a020

27 files changed

+278
-113
lines changed

src/BannedSymbols.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
M:System.Globalization.CompareInfo.IndexOf(System.String,System.Char);CompareInfo.IndexOf can unexpectedly allocate strings--use string.IndexOf
2+
P:Microsoft.Build.Construction.ProjectElementContainer.Children;Use ChildrenEnumerable instead to avoid boxing

src/Build.OM.UnitTests/Construction/ProjectImportElement_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public void ReadNone()
2828
{
2929
ProjectRootElement project = ProjectRootElement.Create();
3030

31-
Assert.Null(project.Imports.GetEnumerator().Current);
31+
Assert.Empty(project.Imports);
3232
}
3333

3434
/// <summary>

src/Build.OM.UnitTests/Construction/ProjectImportGroupElement_Tests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public void ReadNone()
143143
{
144144
ProjectRootElement project = ProjectRootElement.Create();
145145

146-
Assert.Null(project.Imports.GetEnumerator().Current);
146+
Assert.Empty(project.Imports);
147147
}
148148

149149
/// <summary>
@@ -162,7 +162,7 @@ public void ReadNoChild()
162162

163163
ProjectImportGroupElement importGroup = (ProjectImportGroupElement)Helpers.GetFirst(project.ImportGroups);
164164

165-
Assert.Null(project.Imports.GetEnumerator().Current);
165+
Assert.Empty(project.Imports);
166166
Assert.Equal(0, Helpers.Count(importGroup.Imports));
167167
}
168168

src/Build.OM.UnitTests/Construction/ProjectItemDefinitionGroupElement_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void ReadNone()
2424
{
2525
ProjectRootElement project = ProjectRootElement.Create();
2626
Assert.Equal(0, Helpers.Count(project.Children));
27-
Assert.Null(project.ItemDefinitionGroups.GetEnumerator().Current);
27+
Assert.Empty(project.ItemDefinitionGroups);
2828
}
2929

3030
/// <summary>

src/Build.OM.UnitTests/Construction/ProjectItemGroupElement_tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void ReadNoItemGroup()
2424
{
2525
ProjectRootElement project = ProjectRootElement.Create();
2626
Assert.Equal(0, Helpers.Count(project.Children));
27-
Assert.Null(project.ItemGroups.GetEnumerator().Current);
27+
Assert.Empty(project.ItemGroups);
2828
}
2929

3030
/// <summary>

src/Build.OM.UnitTests/Construction/ProjectPropertyGroupElement_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void ReadNoPropertyGroup()
2323
{
2424
ProjectRootElement project = ProjectRootElement.Create();
2525
Assert.Equal(0, Helpers.Count(project.Children));
26-
Assert.Null(project.PropertyGroups.GetEnumerator().Current);
26+
Assert.Empty(project.PropertyGroups);
2727
}
2828

2929
/// <summary>

src/Build.OM.UnitTests/Construction/ProjectTargetElement_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void AddTargetInvalidName()
4141
public void ReadNoTarget()
4242
{
4343
ProjectRootElement project = ProjectRootElement.Create();
44-
Assert.Null(project.Targets.GetEnumerator().Current);
44+
Assert.Empty(project.Targets);
4545
}
4646

4747
/// <summary>

src/Build.OM.UnitTests/Construction/ProjectUsingTaskElement_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public void ReadNone()
2525
{
2626
ProjectRootElement project = ProjectRootElement.Create();
2727

28-
Assert.Null(project.UsingTasks.GetEnumerator().Current);
28+
Assert.Empty(project.UsingTasks);
2929
}
3030

3131
/// <summary>

src/Build.OM.UnitTests/Construction/UsingTaskParameterGroup_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void ReadEmptyParameterGroup()
6565
UsingTaskParameterGroupElement parameterGroup = GetParameterGroupXml(s_contentEmptyParameterGroup);
6666
Assert.NotNull(parameterGroup);
6767
Assert.Equal(0, parameterGroup.Count);
68-
Assert.Null(parameterGroup.Parameters.GetEnumerator().Current);
68+
Assert.Empty(parameterGroup.Parameters);
6969
}
7070

7171
/// <summary>

src/Build/Construction/ProjectChooseElement.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33

44
using System.Collections.Generic;
55
using System.Diagnostics;
6-
using System.Linq;
76
using System.Xml;
8-
using Microsoft.Build.Collections;
97
using Microsoft.Build.ObjectModelRemoting;
108
using Microsoft.Build.Shared;
119

@@ -60,7 +58,7 @@ public override string Condition
6058
/// Get the When children.
6159
/// Will contain at least one entry.
6260
/// </summary>
63-
public ICollection<ProjectWhenElement> WhenElements => new ReadOnlyCollection<ProjectWhenElement>(Children.OfType<ProjectWhenElement>());
61+
public ICollection<ProjectWhenElement> WhenElements => GetChildrenOfType<ProjectWhenElement>();
6462

6563
/// <summary>
6664
/// Get any Otherwise child.

0 commit comments

Comments
 (0)