Skip to content

feat: Optimize OptionCollector by reducing dictionary allocations#1035

Merged
Dor-bl merged 4 commits intoappium:mainfrom
Dor-bl:perf-optimize-option-collector-dictionary-allocation-18318062666670431403
Mar 30, 2026
Merged

feat: Optimize OptionCollector by reducing dictionary allocations#1035
Dor-bl merged 4 commits intoappium:mainfrom
Dor-bl:perf-optimize-option-collector-dictionary-allocation-18318062666670431403

Conversation

@Dor-bl
Copy link
Copy Markdown
Collaborator

@Dor-bl Dor-bl commented Mar 29, 2026

List of changes

This pull request refactors how capabilities are merged and passed to the Appium server in the .NET client, improving code clarity and correctness. It also introduces a new integration test to verify that capabilities are merged as expected when added multiple times.

Capabilities merging and argument handling:

  • Refactored the AddCapabilities method in OptionCollector to directly merge new capabilities into the internal options object, simplifying the logic and reducing unnecessary dictionary copying.
  • Updated ParseCapabilitiesIfWindows and ParseCapabilitiesIfUNIX to accept a capabilities dictionary as a parameter instead of relying on the internal options object, making these methods more flexible and testable. [1] [2]
  • Improved the Arguments property to use the new capability merging logic and pass the merged capabilities dictionary to the parsing methods, ensuring arguments reflect the latest capabilities state. [1] [2]

Testing improvements:

  • Added a new integration test AddCapabilities_MergesCapabilitiesWhenCalledMultipleTimes in AppiumLocalServerLaunchingTest.cs to verify that calling AddCapabilities multiple times correctly merges all provided capabilities into the arguments.

Minor code cleanup:

  • Added a missing using System.Reflection; directive in the test file to support reflection for accessing private properties.

Types of changes

What types of changes are you proposing/introducing to the .NET client?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change that adds functionality or value)
  • Breaking change (fix or feature that would cause existing functionality not to work as expected)
  • Test fix (non-breaking change that improves test stability or correctness)

Documentation

  • Have you proposed a file change/ PR with Appium to update documentation?

This can be done by navigating to the documentation section on http://appium.io selecting the appropriate command/endpoint and clicking the 'Edit this doc' link to update the C# example

Integration tests

  • Have you provided integration tests for your changes? (required for Bugfix, New feature, or Test fix)

Details

Please provide more details about changes if necessary. You can provide code samples showing how they work and possible use cases if there are new features. Also, you can create gists with pasted C# code samples or put them here using markdown.
About markdown please read Mastering markdown and Writing on GitHub

Dor-bl and others added 4 commits March 29, 2026 20:27
…alls

- Refactored `ParseCapabilitiesIfWindows` and `ParseCapabilitiesIfUNIX` to accept a pre-computed dictionary instead of calling `ToDictionary()` internally.
- Updated `Arguments` property getter to call `ToDictionary()` exactly once and reuse the result.
- Optimized `AddCapabilities` to merge options in-place, avoiding multiple dictionary allocations and object re-instantiations.
- Improved efficiency of option collection by reducing O(N) operations and memory pressure.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors how OptionCollector merges Appium capabilities to reduce allocations and ensure the latest merged capabilities are reflected in the Appium server arguments, with an added integration test to validate repeated capability additions.

Changes:

  • Refactored OptionCollector.AddCapabilities to merge directly into the internal options instance instead of rebuilding a merged dictionary.
  • Updated capability parsing helpers to accept a capabilities dictionary parameter and updated Arguments to pass a single merged dictionary through.
  • Added an integration test to verify multiple AddCapabilities calls result in merged capabilities in the generated arguments.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
test/integration/ServerTests/AppiumLocalServerLaunchingTest.cs Adds a test asserting multiple AddCapabilities calls yield merged --default-capabilities output.
src/Appium.Net/Appium/Service/Options/OptionCollector.cs Refactors capability merging/parsing to reduce allocations and centralize merged dictionary handling for argument generation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 44 to 57
public OptionCollector AddCapabilities(AppiumOptions options)
{
if (this.options == null)
{
this.options = options;
}
else
{
IDictionary<string, object> originalDictionary = this.options.ToDictionary();
IDictionary<string, object> givenDictionary = options.ToDictionary();
IDictionary<string, object> result = new Dictionary<string, object>(originalDictionary);

foreach (var item in givenDictionary)
{
if (originalDictionary.ContainsKey(item.Key))
{
result[item.Key] = item.Value;
}
else
{
result.Add(item.Key, item.Value);
}
}

this.options = new AppiumOptions();

foreach (var item in result)
{
this.options.AddAdditionalAppiumOption(item.Key, item.Value);
}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

AddCapabilities now keeps a reference to the first AppiumOptions instance passed in and, on subsequent calls, merges by calling this.options.AddAdditionalAppiumOption(...). This mutates the caller-provided options object (the first one), whereas the previous implementation replaced this.options with a new AppiumOptions when merging, avoiding side effects. To preserve the prior behavior and prevent unexpected external mutation, consider always copying capabilities into an internally-owned AppiumOptions (e.g., initialize this.options as a new AppiumOptions and merge in options.ToDictionary()), rather than storing and mutating the passed-in instance.

Copilot uses AI. Check for mistakes.
@Dor-bl Dor-bl merged commit 37634ed into appium:main Mar 30, 2026
15 checks passed
@Dor-bl Dor-bl deleted the perf-optimize-option-collector-dictionary-allocation-18318062666670431403 branch March 30, 2026 05:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants