Skip to content

Conversation

@paulomorgado
Copy link

Replaced ICollection<string> with HashSet<string> for various properties in the OpenIdConnectConfiguration class

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • If any gains or losses in performance are possible, you've included benchmarks for your changes. More info
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Replaced ICollection<string> with HashSet<string> for various properties in the OpenIdConnectConfiguration class. This change improves performance by utilizing HashSet for faster lookups and uniqueness enforcement. Updated initialization in Interlocked.CompareExchange to ensure efficient collection types are used.

Description

OpenIdConnectConfiguration internally uses System.Collections.ObjectModel.Collection<string> exposed as System.Collections.Generic.ICollection<T>.

However, using System.Collections.ObjectModel.Collection<string> instead of System.Collections.Generic.List<T> has a few drawbacks, namely, Collection<T> introduces a slight overhead due to its virtual methods (InsertItem, RemoveItem, etc.), which can impact performance in high-throughput scenarios while List<T> is optimized for speed and memory usage, making it better for performance-critical applications.

However, I came across WSO2AM Identity Server OIDC discovery endpoint where I found these:

{
  // (...)
  "Response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  // (...)
  "response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  // (...)
}

That results in this deserialization:

ResponseModesSupported	Count = 6	System.Collections.Generic.ICollection<string> {System.Collections.ObjectModel.Collection<string>}
    [0]	"query"
    [1]	"fragment"
    [2]	"form_post"
    [3]	"query"
    [4]	"fragment"
    [5]	"form_post"

Using HashSet<string> would solve this, and add:

  1. Automatic Uniqueness
    • HashSet<string> guarantees no duplicates. If you try to add a duplicate, it simply won’t be added.
    • With List<string>, you’d need to manually check for duplicates using Contains, which is less efficient.
  2. Faster Lookups
    • HashSet<string> uses a hash-based structure, so Contains, Add, and Remove operations are O(1) on average.
    • List<string> uses a linear search, making these operations O(n).
  3. Cleaner Code
    • With HashSet<string>, you don’t need to write extra logic to prevent duplicates or optimize lookups.
    • This leads to simpler and more maintainable code.

It would be better to expose it as Set<string>, but that would be a breaking change.

As for the backing fields for the properties, there's no benefit in erasing their types. Let's keep the real type.

Replaced `ICollection<string>` with `HashSet<string>` for various properties in the `OpenIdConnectConfiguration` class. This change improves performance by utilizing `HashSet` for faster lookups and uniqueness enforcement. Updated initialization in `Interlocked.CompareExchange` to ensure efficient collection types are used.
@paulomorgado paulomorgado requested a review from a team as a code owner July 23, 2025 11:11
@paulomorgado
Copy link
Author

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant