Skip to content

Commit 7b13ea8

Browse files
pentpgfoidl
andauthored
Reduce allocations in Microsoft.Extensions.Configuration (#88211)
Co-authored-by: Günther Foidl <[email protected]>
1 parent e7e9925 commit 7b13ea8

File tree

7 files changed

+32
-30
lines changed

7 files changed

+32
-30
lines changed

src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/ConfigurationPath.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ public static string Combine(IEnumerable<string> pathSegments)
5454
return path;
5555
}
5656

57-
int lastDelimiterIndex = path.LastIndexOf(KeyDelimiter, StringComparison.OrdinalIgnoreCase);
58-
return lastDelimiterIndex == -1 ? path : path.Substring(lastDelimiterIndex + 1);
57+
int lastDelimiterIndex = path.LastIndexOf(':');
58+
return lastDelimiterIndex < 0 ? path : path.Substring(lastDelimiterIndex + 1);
5959
}
6060

6161
/// <summary>
@@ -70,8 +70,8 @@ public static string Combine(IEnumerable<string> pathSegments)
7070
return null;
7171
}
7272

73-
int lastDelimiterIndex = path.LastIndexOf(KeyDelimiter, StringComparison.OrdinalIgnoreCase);
74-
return lastDelimiterIndex == -1 ? null : path.Substring(0, lastDelimiterIndex);
73+
int lastDelimiterIndex = path.LastIndexOf(':');
74+
return lastDelimiterIndex < 0 ? null : path.Substring(0, lastDelimiterIndex);
7575
}
7676
}
7777
}

src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public static class ConfigurationBinder
3535
[RequiresDynamicCode(DynamicCodeWarningMessage)]
3636
[RequiresUnreferencedCode(TrimmingWarningMessage)]
3737
public static T? Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(this IConfiguration configuration)
38-
=> configuration.Get<T>(_ => { });
38+
=> configuration.Get<T>(null);
3939

4040
/// <summary>
4141
/// Attempts to bind the configuration instance to a new instance of type T.
@@ -71,7 +71,7 @@ public static class ConfigurationBinder
7171
[RequiresDynamicCode(DynamicCodeWarningMessage)]
7272
[RequiresUnreferencedCode(TrimmingWarningMessage)]
7373
public static object? Get(this IConfiguration configuration, Type type)
74-
=> configuration.Get(type, _ => { });
74+
=> configuration.Get(type, null);
7575

7676
/// <summary>
7777
/// Attempts to bind the configuration instance to a new instance of type T.
@@ -118,7 +118,7 @@ public static void Bind(this IConfiguration configuration, string key, object? i
118118
[RequiresDynamicCode(DynamicCodeWarningMessage)]
119119
[RequiresUnreferencedCode(InstanceGetTypeTrimmingWarningMessage)]
120120
public static void Bind(this IConfiguration configuration, object? instance)
121-
=> configuration.Bind(instance, _ => { });
121+
=> configuration.Bind(instance, null);
122122

123123
/// <summary>
124124
/// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.
@@ -220,13 +220,16 @@ private static void BindProperties(object instance, IConfiguration configuration
220220
HashSet<string> propertyNames = new(modelProperties.Select(mp => mp.Name),
221221
StringComparer.OrdinalIgnoreCase);
222222

223-
IEnumerable<IConfigurationSection> configurationSections = configuration.GetChildren();
224-
List<string> missingPropertyNames = configurationSections
225-
.Where(cs => !propertyNames.Contains(cs.Key))
226-
.Select(mp => $"'{mp.Key}'")
227-
.ToList();
223+
List<string>? missingPropertyNames = null;
224+
foreach (IConfigurationSection cs in configuration.GetChildren())
225+
{
226+
if (!propertyNames.Contains(cs.Key))
227+
{
228+
(missingPropertyNames ??= new()).Add($"'{cs.Key}'");
229+
}
230+
}
228231

229-
if (missingPropertyNames.Count > 0)
232+
if (missingPropertyNames != null)
230233
{
231234
throw new InvalidOperationException(SR.Format(SR.Error_MissingConfig,
232235
nameof(options.ErrorOnUnknownConfiguration), nameof(BinderOptions), instance.GetType(),
@@ -381,7 +384,7 @@ private static void BindInstance(
381384
(interfaceGenericType == typeof(ICollection<>) || interfaceGenericType == typeof(IList<>)))
382385
{
383386
// For ICollection<T> and IList<T> we bind them to mutable List<T> type.
384-
Type genericType = typeof(List<>).MakeGenericType(type.GenericTypeArguments[0]);
387+
Type genericType = typeof(List<>).MakeGenericType(type.GenericTypeArguments);
385388
bindingPoint.SetValue(Activator.CreateInstance(genericType));
386389
}
387390
else

src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationBuilder.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ namespace Microsoft.Extensions.Configuration
1111
/// </summary>
1212
public class ConfigurationBuilder : IConfigurationBuilder
1313
{
14+
private readonly List<IConfigurationSource> _sources = new();
15+
1416
/// <summary>
1517
/// Returns the sources used to obtain configuration values.
1618
/// </summary>
17-
public IList<IConfigurationSource> Sources { get; } = new List<IConfigurationSource>();
19+
public IList<IConfigurationSource> Sources => _sources;
1820

1921
/// <summary>
2022
/// Gets a key/value collection that can be used to share data between the <see cref="IConfigurationBuilder"/>
@@ -31,7 +33,7 @@ public IConfigurationBuilder Add(IConfigurationSource source)
3133
{
3234
ThrowHelper.ThrowIfNull(source);
3335

34-
Sources.Add(source);
36+
_sources.Add(source);
3537
return this;
3638
}
3739

@@ -43,7 +45,7 @@ public IConfigurationBuilder Add(IConfigurationSource source)
4345
public IConfigurationRoot Build()
4446
{
4547
var providers = new List<IConfigurationProvider>();
46-
foreach (IConfigurationSource source in Sources)
48+
foreach (IConfigurationSource source in _sources)
4749
{
4850
IConfigurationProvider provider = source.Build(this);
4951
providers.Add(provider);

src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationManager.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,7 @@ public void CopyTo(IConfigurationSource[] array, int arrayIndex)
229229
_sources.CopyTo(array, arrayIndex);
230230
}
231231

232-
public IEnumerator<IConfigurationSource> GetEnumerator()
233-
{
234-
return _sources.GetEnumerator();
235-
}
232+
public List<IConfigurationSource>.Enumerator GetEnumerator() => _sources.GetEnumerator();
236233

237234
public int IndexOf(IConfigurationSource source)
238235
{
@@ -258,10 +255,9 @@ public void RemoveAt(int index)
258255
_config.ReloadSources();
259256
}
260257

261-
IEnumerator IEnumerable.GetEnumerator()
262-
{
263-
return GetEnumerator();
264-
}
258+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
259+
260+
IEnumerator<IConfigurationSource> IEnumerable<IConfigurationSource>.GetEnumerator() => GetEnumerator();
265261
}
266262

267263
private sealed class ConfigurationBuilderProperties : IDictionary<string, object>

src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ public virtual IEnumerable<string> GetChildKeys(
9595

9696
private static string Segment(string key, int prefixLength)
9797
{
98-
int indexOf = key.IndexOf(ConfigurationPath.KeyDelimiter, prefixLength, StringComparison.OrdinalIgnoreCase);
98+
Debug.Assert(ConfigurationPath.KeyDelimiter == ":");
99+
int indexOf = key.IndexOf(':', prefixLength);
99100
return indexOf < 0 ? key.Substring(prefixLength) : key.Substring(prefixLength, indexOf - prefixLength);
100101
}
101102

src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationSection.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ public string? this[string key]
6969
{
7070
get
7171
{
72-
return _root[ConfigurationPath.Combine(Path, key)];
72+
return _root[Path + ConfigurationPath.KeyDelimiter + key];
7373
}
7474
set
7575
{
76-
_root[ConfigurationPath.Combine(Path, key)] = value;
76+
_root[Path + ConfigurationPath.KeyDelimiter + key] = value;
7777
}
7878
}
7979

@@ -86,7 +86,7 @@ public string? this[string key]
8686
/// This method will never return <c>null</c>. If no matching sub-section is found with the specified key,
8787
/// an empty <see cref="IConfigurationSection"/> will be returned.
8888
/// </remarks>
89-
public IConfigurationSection GetSection(string key) => _root.GetSection(ConfigurationPath.Combine(Path, key));
89+
public IConfigurationSection GetSection(string key) => _root.GetSection(Path + ConfigurationPath.KeyDelimiter + key);
9090

9191
/// <summary>
9292
/// Gets the immediate descendant configuration sub-sections.

src/libraries/Microsoft.Extensions.Configuration/src/InternalConfigurationRootExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ internal static IEnumerable<IConfigurationSection> GetChildrenImplementation(thi
2727
.Aggregate(Enumerable.Empty<string>(),
2828
(seed, source) => source.GetChildKeys(seed, path))
2929
.Distinct(StringComparer.OrdinalIgnoreCase)
30-
.Select(key => root.GetSection(path == null ? key : ConfigurationPath.Combine(path, key)));
30+
.Select(key => root.GetSection(path == null ? key : path + ConfigurationPath.KeyDelimiter + key));
3131

3232
if (reference is null)
3333
{

0 commit comments

Comments
 (0)