Skip to content

Commit 3604382

Browse files
feat: Remove default collection initialization for perf reasons (#2284)
* feat: use lazy get for collection initialization to reduce resource allocation * chore: use Lazy<T> pattern; preserve null values * chore: replicate for collections in other components * chore: remove unnecessary usings * fix: revert lazy initialization; remove collection initialization * chore: initialize collections to prevent NREs * chore: fix failing tests * chore: revert changes * chore: remove default collection initialization across all models; clean up and fix tests * chore: clean up code; initialize collections where applicable * chore: more cleanup * chore: move assignment within the condition * chore: replace interface with concrete type * chore: simplify collection initialization * Update src/Microsoft.OpenApi/Models/OpenApiPathItem.cs Co-authored-by: Vincent Biret <vibiret@microsoft.com> * chore: implement PR feedback * chore: reverts casing change --------- Co-authored-by: Vincent Biret <vibiret@microsoft.com>
1 parent 136a724 commit 3604382

File tree

142 files changed

+1357
-1318
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+1357
-1318
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ var document = new OpenApiDocument
5555
{
5656
["/pets"] = new OpenApiPathItem
5757
{
58-
Operations = new Dictionary<HttpMethod, OpenApiOperation>
58+
Operations = new()
5959
{
6060
[HttpMethod.Get] = new OpenApiOperation
6161
{

src/Microsoft.OpenApi.Hidi/Extensions/OpenApiExtensibleExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal static class OpenApiExtensibleExtensions
1313
/// <param name="extensions">A dictionary of <see cref="IOpenApiExtension"/>.</param>
1414
/// <param name="extensionKey">The key corresponding to the <see cref="IOpenApiExtension"/>.</param>
1515
/// <returns>A <see cref="string"/> value matching the provided extensionKey. Return null when extensionKey is not found. </returns>
16-
internal static string GetExtension(this IDictionary<string, IOpenApiExtension> extensions, string extensionKey)
16+
internal static string GetExtension(this Dictionary<string, IOpenApiExtension> extensions, string extensionKey)
1717
{
1818
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny { Node: JsonValue castValue } && castValue.TryGetValue<string>(out var stringValue))
1919
{

src/Microsoft.OpenApi.Hidi/Extensions/StringExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public static bool IsEquals(this string? target, string? searchValue, StringComp
3434
/// <param name="target">The target string to split by char. </param>
3535
/// <param name="separator">The char separator.</param>
3636
/// <returns>An <see cref="IList{String}"/> containing substrings.</returns>
37-
public static IList<string> SplitByChar(this string target, char separator)
37+
public static List<string> SplitByChar(this string target, char separator)
3838
{
3939
if (string.IsNullOrWhiteSpace(target))
4040
{

src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public override void Visit(OpenApiOperation operation)
7777
// Order matters. Resolve operationId.
7878
operationId = RemoveHashSuffix(operationId);
7979
if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function"))
80-
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List<IOpenApiParameter>());
80+
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? []);
8181
operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.'));
8282
operationId = ResolveODataCastOperationId(operationId);
8383
operationId = ResolveByRefOperationId(operationId);
@@ -119,7 +119,7 @@ private static string ResolveODataCastOperationId(string operationId)
119119
return match.Success ? $"{match.Groups[1]}{match.Groups[2]}" : operationId;
120120
}
121121

122-
private static string SingularizeAndDeduplicateOperationId(IList<string> operationIdSegments)
122+
private static string SingularizeAndDeduplicateOperationId(List<string> operationIdSegments)
123123
{
124124
var segmentsCount = operationIdSegments.Count;
125125
var lastSegmentIndex = segmentsCount - 1;
@@ -145,7 +145,7 @@ private static string RemoveHashSuffix(string operationId)
145145
return s_hashSuffixRegex.Match(operationId).Value;
146146
}
147147

148-
private static string RemoveKeyTypeSegment(string operationId, IList<IOpenApiParameter> parameters)
148+
private static string RemoveKeyTypeSegment(string operationId, List<IOpenApiParameter> parameters)
149149
{
150150
var segments = operationId.SplitByChar('.');
151151
foreach (var parameter in parameters)
@@ -159,9 +159,9 @@ private static string RemoveKeyTypeSegment(string operationId, IList<IOpenApiPar
159159
return string.Join('.', segments);
160160
}
161161

162-
private static void ResolveFunctionParameters(IList<IOpenApiParameter> parameters)
162+
private static void ResolveFunctionParameters(List<IOpenApiParameter> parameters)
163163
{
164-
foreach (var parameter in parameters.OfType<OpenApiParameter>().Where(static p => p.Content?.Any() ?? false))
164+
foreach (var parameter in parameters.OfType<OpenApiParameter>().Where(static p => p.Content?.Count > 0))
165165
{
166166
// Replace content with a schema object of type array
167167
// for structured or collection-valued function parameters

src/Microsoft.OpenApi.Hidi/StatsVisitor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public override void Visit(IOpenApiSchema schema)
2727

2828
public int HeaderCount { get; set; }
2929

30-
public override void Visit(IDictionary<string, IOpenApiHeader> headers)
30+
public override void Visit(Dictionary<string, IOpenApiHeader> headers)
3131
{
3232
HeaderCount++;
3333
}

src/Microsoft.OpenApi.Workbench/StatsVisitor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public override void Visit(IOpenApiSchema schema)
2727

2828
public int HeaderCount { get; set; }
2929

30-
public override void Visit(IDictionary<string, IOpenApiHeader> headers)
30+
public override void Visit(Dictionary<string, IOpenApiHeader> headers)
3131
{
3232
HeaderCount++;
3333
}

src/Microsoft.OpenApi/Extensions/OpenApiExtensibleExtensions.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using Microsoft.OpenApi.Exceptions;
67
using Microsoft.OpenApi.Interfaces;
78
using Microsoft.OpenApi.Models;
@@ -32,10 +33,8 @@ public static void AddExtension<T>(this T element, string name, IOpenApiExtensio
3233
throw new OpenApiException(string.Format(SRResource.ExtensionFieldNameMustBeginWithXDash, name));
3334
}
3435

35-
if (element.Extensions is not null)
36-
{
37-
element.Extensions[name] = Utils.CheckArgumentNull(any);
38-
}
36+
element.Extensions ??= [];
37+
element.Extensions[name] = Utils.CheckArgumentNull(any);
3938
}
4039
}
4140
}

src/Microsoft.OpenApi/Extensions/OpenApiServerExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static class OpenApiServerExtensions
2121
/// 1. A substitution has no valid value in both the supplied dictionary and the default
2222
/// 2. A substitution's value is not available in the enum provided
2323
/// </exception>
24-
public static string? ReplaceServerUrlVariables(this OpenApiServer server, IDictionary<string, string>? values = null)
24+
public static string? ReplaceServerUrlVariables(this OpenApiServer server, Dictionary<string, string>? values = null)
2525
{
2626
var parsedUrl = server.Url;
2727
if (server.Variables is not null && parsedUrl is not null)

src/Microsoft.OpenApi/Interfaces/IMetadataContainer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ public interface IMetadataContainer
1414
/// <summary>
1515
/// A collection of properties associated with the current OpenAPI element.
1616
/// </summary>
17-
IDictionary<string, object>? Metadata { get; set; }
17+
Dictionary<string, object>? Metadata { get; set; }
1818
}
1919
}

src/Microsoft.OpenApi/Interfaces/IOpenApiExtensible.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ public interface IOpenApiExtensible : IOpenApiElement
1313
/// <summary>
1414
/// Specification extensions.
1515
/// </summary>
16-
IDictionary<string, IOpenApiExtension>? Extensions { get; set; }
16+
Dictionary<string, IOpenApiExtension>? Extensions { get; set; }
1717
}
1818
}

src/Microsoft.OpenApi/Interfaces/IOpenApiReadOnlyExtensible.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ public interface IOpenApiReadOnlyExtensible
1010
/// <summary>
1111
/// Specification extensions.
1212
/// </summary>
13-
IDictionary<string, IOpenApiExtension>? Extensions { get; }
13+
Dictionary<string, IOpenApiExtension>? Extensions { get; }
1414

1515
}

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ public interface IOpenApiHeader : IOpenApiDescribedElement, IOpenApiReadOnlyExte
5555
/// <summary>
5656
/// Examples of the media type.
5757
/// </summary>
58-
public IDictionary<string, IOpenApiExample>? Examples { get; }
58+
public Dictionary<string, IOpenApiExample>? Examples { get; }
5959

6060
/// <summary>
6161
/// A map containing the representations for the header.
6262
/// </summary>
63-
public IDictionary<string, OpenApiMediaType>? Content { get; }
63+
public Dictionary<string, OpenApiMediaType>? Content { get; }
6464

6565
}

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public interface IOpenApiLink : IOpenApiDescribedElement, IOpenApiReadOnlyExtens
2424
/// <summary>
2525
/// A map representing parameters to pass to an operation as specified with operationId or identified via operationRef.
2626
/// </summary>
27-
public IDictionary<string, RuntimeExpressionAnyWrapper>? Parameters { get; }
27+
public Dictionary<string, RuntimeExpressionAnyWrapper>? Parameters { get; }
2828

2929
/// <summary>
3030
/// A literal value or {expression} to use as a request body when calling the target operation.

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiParameter.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiReadOnlyE
8181
/// Furthermore, if referencing a schema which contains an example,
8282
/// the examples value SHALL override the example provided by the schema.
8383
/// </summary>
84-
public IDictionary<string, IOpenApiExample>? Examples { get; }
84+
public Dictionary<string, IOpenApiExample>? Examples { get; }
8585

8686
/// <summary>
8787
/// Example of the media type. The example SHOULD match the specified schema and encoding properties
@@ -102,5 +102,5 @@ public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiReadOnlyE
102102
/// When example or examples are provided in conjunction with the schema object,
103103
/// the example MUST follow the prescribed serialization strategy for the parameter.
104104
/// </summary>
105-
public IDictionary<string, OpenApiMediaType>? Content { get; }
105+
public Dictionary<string, OpenApiMediaType>? Content { get; }
106106
}

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ public interface IOpenApiPathItem : IOpenApiDescribedElement, IOpenApiSummarized
1414
/// <summary>
1515
/// Gets the definition of operations on this path.
1616
/// </summary>
17-
public IDictionary<HttpMethod, OpenApiOperation>? Operations { get; }
17+
public Dictionary<HttpMethod, OpenApiOperation>? Operations { get; }
1818

1919
/// <summary>
2020
/// An alternative server array to service all operations in this path.
2121
/// </summary>
22-
public IList<OpenApiServer>? Servers { get; }
22+
public List<OpenApiServer>? Servers { get; }
2323

2424
/// <summary>
2525
/// A list of parameters that are applicable for all the operations described under this path.
2626
/// These parameters can be overridden at the operation level, but cannot be removed there.
2727
/// </summary>
28-
public IList<IOpenApiParameter>? Parameters { get; }
28+
public List<IOpenApiParameter>? Parameters { get; }
2929
}

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiRequestBody.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public interface IOpenApiRequestBody : IOpenApiDescribedElement, IOpenApiReadOnl
1919
/// REQUIRED. The content of the request body. The key is a media type or media type range and the value describes it.
2020
/// For requests that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/*
2121
/// </summary>
22-
public IDictionary<string, OpenApiMediaType>? Content { get; }
22+
public Dictionary<string, OpenApiMediaType>? Content { get; }
2323
/// <summary>
2424
/// Converts the request body to a body parameter in preparation for a v2 serialization.
2525
/// </summary>

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ public interface IOpenApiResponse : IOpenApiDescribedElement, IOpenApiReadOnlyEx
1212
/// <summary>
1313
/// Maps a header name to its definition.
1414
/// </summary>
15-
public IDictionary<string, IOpenApiHeader>? Headers { get; }
15+
public Dictionary<string, IOpenApiHeader>? Headers { get; }
1616

1717
/// <summary>
1818
/// A map containing descriptions of potential response payloads.
1919
/// The key is a media type or media type range and the value describes it.
2020
/// </summary>
21-
public IDictionary<string, OpenApiMediaType>? Content { get; }
21+
public Dictionary<string, OpenApiMediaType>? Content { get; }
2222

2323
/// <summary>
2424
/// A map of operations links that can be followed from the response.
2525
/// The key of the map is a short name for the link,
2626
/// following the naming constraints of the names for Component Objects.
2727
/// </summary>
28-
public IDictionary<string, IOpenApiLink>? Links { get; }
28+
public Dictionary<string, IOpenApiLink>? Links { get; }
2929
}

src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs

+13-13
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
3535
/// <summary>
3636
/// $vocabulary- used in meta-schemas to identify the vocabularies available for use in schemas described by that meta-schema.
3737
/// </summary>
38-
public IDictionary<string, bool>? Vocabulary { get; }
38+
public Dictionary<string, bool>? Vocabulary { get; }
3939

4040
/// <summary>
4141
/// $dynamicRef - an applicator that allows for deferring the full resolution until runtime, at which point it is resolved each time it is encountered while evaluating an instance
@@ -51,7 +51,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
5151
/// $defs - reserves a location for schema authors to inline re-usable JSON Schemas into a more general schema.
5252
/// The keyword does not directly affect the validation result
5353
/// </summary>
54-
public IDictionary<string, IOpenApiSchema>? Definitions { get; }
54+
public Dictionary<string, IOpenApiSchema>? Definitions { get; }
5555

5656
/// <summary>
5757
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
@@ -144,19 +144,19 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
144144
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
145145
/// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
146146
/// </summary>
147-
public IList<IOpenApiSchema>? AllOf { get; }
147+
public List<IOpenApiSchema>? AllOf { get; }
148148

149149
/// <summary>
150150
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
151151
/// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
152152
/// </summary>
153-
public IList<IOpenApiSchema>? OneOf { get; }
153+
public List<IOpenApiSchema>? OneOf { get; }
154154

155155
/// <summary>
156156
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
157157
/// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
158158
/// </summary>
159-
public IList<IOpenApiSchema>? AnyOf { get; }
159+
public List<IOpenApiSchema>? AnyOf { get; }
160160

161161
/// <summary>
162162
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
@@ -167,7 +167,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
167167
/// <summary>
168168
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
169169
/// </summary>
170-
public ISet<string>? Required { get; }
170+
public HashSet<string>? Required { get; }
171171

172172
/// <summary>
173173
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
@@ -195,7 +195,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
195195
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
196196
/// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced).
197197
/// </summary>
198-
public IDictionary<string, IOpenApiSchema>? Properties { get; }
198+
public Dictionary<string, IOpenApiSchema>? Properties { get; }
199199

200200
/// <summary>
201201
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
@@ -204,7 +204,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
204204
/// egular expression dialect. Each property value of this object MUST be an object, and each object MUST
205205
/// be a valid Schema Object not a standard JSON Schema.
206206
/// </summary>
207-
public IDictionary<string, IOpenApiSchema>? PatternProperties { get; }
207+
public Dictionary<string, IOpenApiSchema>? PatternProperties { get; }
208208

209209
/// <summary>
210210
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
@@ -246,12 +246,12 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
246246
/// To represent examples that cannot be naturally represented in JSON or YAML,
247247
/// a list of values can be used to contain the examples with escaping where necessary.
248248
/// </summary>
249-
public IList<JsonNode>? Examples { get; }
249+
public List<JsonNode>? Examples { get; }
250250

251251
/// <summary>
252252
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
253253
/// </summary>
254-
public IList<JsonNode>? Enum { get; }
254+
public List<JsonNode>? Enum { get; }
255255

256256
/// <summary>
257257
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
@@ -278,16 +278,16 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
278278
/// <summary>
279279
/// This object stores any unrecognized keywords found in the schema.
280280
/// </summary>
281-
public IDictionary<string, JsonNode>? UnrecognizedKeywords { get; }
281+
public Dictionary<string, JsonNode>? UnrecognizedKeywords { get; }
282282

283283
/// <summary>
284284
/// Any annotation to attach to the schema to be used by the application.
285285
/// Annotations are NOT (de)serialized with the schema and can be used for custom properties.
286286
/// </summary>
287-
public IDictionary<string, object>? Annotations { get; }
287+
public Dictionary<string, object>? Annotations { get; }
288288

289289
/// <summary>
290290
/// Follow JSON Schema definition:https://json-schema.org/draft/2020-12/json-schema-validation#section-6.5.4
291291
/// </summary>
292-
public IDictionary<string, ISet<string>>? DependentRequired { get; }
292+
public Dictionary<string, HashSet<string>>? DependentRequired { get; }
293293
}

src/Microsoft.OpenApi/Models/OpenApiCallback.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@ namespace Microsoft.OpenApi.Models
1313
/// <summary>
1414
/// Callback Object: A map of possible out-of band callbacks related to the parent operation.
1515
/// </summary>
16-
public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiCallback
16+
public class OpenApiCallback : IOpenApiExtensible, IOpenApiCallback
1717
{
1818
/// <inheritdoc/>
1919
public Dictionary<RuntimeExpression, IOpenApiPathItem>? PathItems { get; set; }
20-
= [];
2120

2221

2322
/// <summary>
2423
/// This object MAY be extended with Specification Extensions.
2524
/// </summary>
26-
public IDictionary<string, IOpenApiExtension>? Extensions { get; set; } = new Dictionary<string, IOpenApiExtension>();
25+
public Dictionary<string, IOpenApiExtension>? Extensions { get; set; }
2726

2827
/// <summary>
2928
/// Parameter-less constructor

0 commit comments

Comments
 (0)