Skip to content
2 changes: 1 addition & 1 deletion eng/Common.globalconfig
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ dotnet_diagnostic.CA1834.severity = suggestion
dotnet_diagnostic.CA1835.severity = suggestion

# Prefer IsEmpty over Count
dotnet_diagnostic.CA1836.severity = suggestion
dotnet_diagnostic.CA1836.severity = warning

# Use 'Environment.ProcessId'
dotnet_diagnostic.CA1837.severity = suggestion
Expand Down
2 changes: 1 addition & 1 deletion src/Build.UnitTests/ProjectCache/ProjectCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public ProjectCacheTests(ITestOutputHelper output)
_env = TestEnvironment.Create(output);

BuildManager.ProjectCacheItems.ShouldBeEmpty();
_env.WithInvariant(new CustomConditionInvariant(() => BuildManager.ProjectCacheItems.Count == 0));
_env.WithInvariant(new CustomConditionInvariant(() => BuildManager.ProjectCacheItems.IsEmpty));
}

public void Dispose()
Expand Down
4 changes: 2 additions & 2 deletions src/Build/BackEnd/BuildManager/BuildManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ bool ProjectCacheIsPresent()

private static bool ProjectCachePresentViaVisualStudioWorkaround()
{
return BuildEnvironmentHelper.Instance.RunningInVisualStudio && ProjectCacheItems.Count > 0;
return BuildEnvironmentHelper.Instance.RunningInVisualStudio && ProjectCacheItems.Any();
}

// Cache requests on configuration N do not block future build submissions depending on configuration N.
Expand Down Expand Up @@ -1261,7 +1261,7 @@ private ProjectCacheService GetProjectCacheService()
private void AutomaticallyDetectAndInstantiateProjectCacheServiceForVisualStudio()
{
if (BuildEnvironmentHelper.Instance.RunningInVisualStudio &&
ProjectCacheItems.Count > 0 &&
ProjectCacheItems.Any() &&
_projectCacheService == null &&
_buildParameters.ProjectCacheDescriptor == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public void ContinueRequestWithResources(ResourceResponse response)
{
ErrorUtilities.VerifyThrow(HasActiveBuildRequest, "Request not building");
ErrorUtilities.VerifyThrow(!_terminateEvent.WaitOne(0), "Request already terminated");
ErrorUtilities.VerifyThrow(!_pendingResourceRequests.IsEmpty, "No pending resource requests");
ErrorUtilities.VerifyThrow(_pendingResourceRequests.Any(), "No pending resource requests");
VerifyEntryInActiveOrWaitingState();

_pendingResourceRequests.Dequeue()(response);
Expand Down
5 changes: 3 additions & 2 deletions src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using ElementLocation = Microsoft.Build.Construction.ElementLocation;
using BuildAbortedException = Microsoft.Build.Exceptions.BuildAbortedException;
using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem;
using System.Linq;

#nullable disable

Expand Down Expand Up @@ -405,7 +406,7 @@ private async Task ProcessTargetStack(ITaskBuilder taskBuilder)
(
!_cancellationToken.IsCancellationRequested &&
!stopProcessingStack &&
!_targetsToBuild.IsEmpty
_targetsToBuild.Any()
)
{
TargetEntry currentTargetEntry = _targetsToBuild.Peek();
Expand Down Expand Up @@ -613,7 +614,7 @@ private void PopDependencyTargetsOnTargetFailure(TargetEntry topEntry, TargetRes
// Pop down to our parent, since any other dependencies our parent had should no longer
// execute. If we encounter an error target on the way down, also stop since the failure
// of one error target in a set declared in OnError should not cause the others to stop running.
while ((!_targetsToBuild.IsEmpty) && (_targetsToBuild.Peek() != topEntry.ParentEntry) && !_targetsToBuild.Peek().ErrorTarget)
while ((_targetsToBuild.Any()) && (_targetsToBuild.Peek() != topEntry.ParentEntry) && !_targetsToBuild.Peek().ErrorTarget)
{
TargetEntry entry = _targetsToBuild.Pop();
entry.LeaveLegacyCallTargetScopes();
Expand Down
4 changes: 2 additions & 2 deletions src/Build/Evaluation/LazyItemEvaluator.RemoveOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public RemoveOperation(RemoveOperationBuilder builder, LazyItemEvaluator<P, I, M
new BuildEventFileInfo(string.Empty),
"OM_MatchOnMetadataIsRestrictedToReferencedItems");

if (!_matchOnMetadata.IsEmpty)
if (_matchOnMetadata.Any())
{
_metadataSet = new MetadataTrie<P, I>(builder.MatchOnMetadataOptions, _matchOnMetadata, _itemSpec);
}
Expand All @@ -49,7 +49,7 @@ protected override void ApplyImpl(OrderedItemDataCollection.Builder listBuilder,
return;
}

bool matchingOnMetadata = !_matchOnMetadata.IsEmpty;
bool matchingOnMetadata = _matchOnMetadata.Any();
if (!matchingOnMetadata)
{
if (ItemspecContainsASingleBareItemReference(_itemSpec, _itemElement.ItemType))
Expand Down
2 changes: 1 addition & 1 deletion src/Build/Logging/ProfilerLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ internal ProfilerResult GetAggregatedResult(bool pruneSmallItems = true)
// So keeping that map here
var originalLocations = new Dictionary<EvaluationLocation, EvaluationLocation>(EvaluationLocationIdAgnosticComparer.Singleton);

while (!_profiledResults.IsEmpty)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Forgind when we were talking about this did we talk about .Any() possibly being worse than ! .IsEmpty because the former is an extension method that might have higher overhead?

Method ActuallyEmpty Mean Error StdDev Allocated
IsEmpty False 2.484 ns 0.0534 ns 0.0473 ns -
Any False 1,361.709 ns 5.7049 ns 5.0573 ns -
IsEmpty True 178.694 ns 1.1384 ns 1.0649 ns -
Any True 177.720 ns 1.7098 ns 1.5993 ns -
using System;
using System.Collections.Concurrent;
using System.Linq;

using BenchmarkDotNet;
using BenchmarkDotNet.Attributes;

namespace any_count;

[MemoryDiagnoser]
public class Benchmarks
{
    public static ConcurrentDictionary<string, string> emptyDictionary = new ConcurrentDictionary<string, string>();

    public static ConcurrentDictionary<string, string> nonEmptyDictionary = new ConcurrentDictionary<string, string>();

    static Benchmarks()
    {
        for (int i = 0; i < 100; i++)
        {
            nonEmptyDictionary.TryAdd(i.ToString(), i.ToString());
        }
    }

    [Params(true, false)]
    public bool ActuallyEmpty;

    [Benchmark]
    public bool IsEmpty() => (ActuallyEmpty? emptyDictionary : nonEmptyDictionary).IsEmpty;

    [Benchmark]
    public bool Any() => (ActuallyEmpty? emptyDictionary : nonEmptyDictionary).Any();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Forgind when we were talking about this did we talk about .Any() possibly being worse than ! .IsEmpty because the former is an extension method that might have higher overhead?

Oh, I'm sorry; I didn't add a new comment after that part, and it slipped my mind. So do you think it's worth replacing .Any() with !.IsEmpty? (If so, sorry elachlan...)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Forgind when we were talking about this did we talk about .Any() possibly being worse than ! .IsEmpty because the former is an extension method that might have higher overhead?

Oh, I'm sorry; I didn't add a new comment after that part, and it slipped my mind. So do you think it's worth replacing .Any() with !.IsEmpty? (If so, sorry elachlan...)

I am happy to. I will make another PR and replace all any calls where I can. That time difference is massive.

while (_profiledResults.Any())
{
ProfilerResult profiledResult;
var result = _profiledResults.TryDequeue(out profiledResult);
Expand Down
2 changes: 1 addition & 1 deletion src/Shared/RegisteredTaskObjectCacheBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public object UnregisterTaskObject(object key, RegisteredTaskObjectLifetime life
protected bool IsCollectionEmptyOrUncreated(RegisteredTaskObjectLifetime lifetime)
{
var collection = GetCollectionForLifetime(lifetime, dontCreate: true);
return (collection == null) || (collection.Count == 0);
return (collection == null) || collection.IsEmpty;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Tasks/GetSDKReferenceFiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ internal bool Execute(GetAssemblyName getAssemblyName, GetAssemblyRuntimeVersion

GenerateOutputItems();

if (_exceptions.Count > 0 && LogCacheFileExceptions)
if (_exceptions.Any() && LogCacheFileExceptions)
{
foreach (string exceptionMessage in _exceptions)
{
Expand Down