diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs index b4094fe54de20a..29c38881eec080 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs @@ -15,7 +15,7 @@ public class OptionsCache<[DynamicallyAccessedMembers(Options.DynamicallyAccesse IOptionsMonitorCache where TOptions : class { - private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>(StringComparer.Ordinal); + private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>(concurrencyLevel: 1, capacity: 31, StringComparer.Ordinal); // 31 == default capacity /// /// Clears all options instances from the cache. @@ -38,6 +38,24 @@ public virtual TOptions GetOrAdd(string name, Func createOptions) return _cache.GetOrAdd(name, new Lazy(createOptions)).Value; } + /// + /// Gets a named options instance, if available. + /// + /// The name of the options instance. + /// The options instance. + /// true if the options were retrieved; otherwise, false. + internal bool TryGetValue(string name, out TOptions options) + { + if (_cache.TryGetValue(name ?? Options.DefaultName, out Lazy lazy)) + { + options = lazy.Value; + return true; + } + + options = default; + return false; + } + /// /// Tries to adds a new option to the cache, will return false if the name already exists. /// diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs index 71b5a134f35139..83fc0ecc8e9050 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs @@ -29,13 +29,7 @@ public OptionsManager(IOptionsFactory factory) /// /// The default configured instance, equivalent to Get(Options.DefaultName). /// - public TOptions Value - { - get - { - return Get(Options.DefaultName); - } - } + public TOptions Value => Get(Options.DefaultName); /// /// Returns a configured instance with the given . @@ -44,8 +38,15 @@ public virtual TOptions Get(string name) { name = name ?? Options.DefaultName; - // Store the options in our instance cache - return _cache.GetOrAdd(name, () => _factory.Create(name)); + if (!_cache.TryGetValue(name, out TOptions options)) + { + // Store the options in our instance cache. Avoid closure on fast path by storing state into scoped locals. + IOptionsFactory localFactory = _factory; + string localName = name; + options = _cache.GetOrAdd(name, () => localFactory.Create(localName)); + } + + return options; } } }