Header menu logo G-Research F# Analyzers

JsonSerializerOptionsAnalyzer

Problem

The Performance Improvements in .NET 8 blog post mentions JsonSerializerOptions from System.Text.Json is deceptively expensive to create, so calls to JsonSerializer.{De}Serialize should use a cached instance rather than newing one up each time.

open System.Text.Json

let f (json: string) (jsonStream: System.IO.Stream) =
    let _ = JsonSerializer.Deserialize<string>(json, JsonSerializerOptions ())
    let _ = JsonSerializer.DeserializeAsync<string>(jsonStream, JsonSerializerOptions ())
    let _ = JsonSerializer.DeserializeAsyncEnumerable<string>(jsonStream, JsonSerializerOptions ())
    ()

Fix

Try and cache the JsonSerializerOptions instance:

open System.Text.Json

let f (json : string) (jsonStream : System.IO.Stream) =
    let options = JsonSerializerOptions ()
    let _ = JsonSerializer.Deserialize<string>(json, options)
    let _ = JsonSerializer.DeserializeAsync<string>(jsonStream, options)
    let _ = JsonSerializer.DeserializeAsyncEnumerable<string>(jsonStream, options)
    ()
namespace System
namespace System.Text
namespace System.Text.Json
val f: json: string -> jsonStream: System.IO.Stream -> unit
val json: string
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val jsonStream: System.IO.Stream
namespace System.IO
type Stream = inherit MarshalByRefObject interface IAsyncDisposable interface IDisposable member BeginRead: buffer: byte array * offset: int * count: int * callback: AsyncCallback * state: obj -> IAsyncResult member BeginWrite: buffer: byte array * offset: int * count: int * callback: AsyncCallback * state: obj -> IAsyncResult member Close: unit -> unit member CopyTo: destination: Stream -> unit + 1 overload member CopyToAsync: destination: Stream -> Task + 3 overloads member Dispose: unit -> unit member DisposeAsync: unit -> ValueTask ...
<summary>Provides a generic view of a sequence of bytes. This is an abstract class.</summary>
type JsonSerializer = static member Deserialize: utf8Json: Stream * jsonTypeInfo: JsonTypeInfo -> obj + 39 overloads static member DeserializeAsync: utf8Json: Stream * jsonTypeInfo: JsonTypeInfo * ?cancellationToken: CancellationToken -> ValueTask<obj> + 4 overloads static member DeserializeAsyncEnumerable<'TValue> : utf8Json: Stream * ?options: JsonSerializerOptions * ?cancellationToken: CancellationToken -> IAsyncEnumerable<'TValue> + 1 overload static member Serialize: utf8Json: Stream * value: obj * jsonTypeInfo: JsonTypeInfo -> unit + 14 overloads static member SerializeAsync: utf8Json: Stream * value: obj * jsonTypeInfo: JsonTypeInfo * ?cancellationToken: CancellationToken -> Task + 4 overloads static member SerializeToDocument: value: obj * jsonTypeInfo: JsonTypeInfo -> JsonDocument + 4 overloads static member SerializeToElement: value: obj * jsonTypeInfo: JsonTypeInfo -> JsonElement + 4 overloads static member SerializeToNode: value: obj * jsonTypeInfo: JsonTypeInfo -> JsonNode + 4 overloads static member SerializeToUtf8Bytes: value: obj * jsonTypeInfo: JsonTypeInfo -> byte array + 4 overloads static member IsReflectionEnabledByDefault: bool
<summary>Provides functionality to serialize objects or value types to JSON and to deserialize JSON into objects or value types.</summary>
JsonSerializer.Deserialize<'TValue>(reader: byref<Utf8JsonReader>, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo<'TValue>) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(reader: byref<Utf8JsonReader>, ?options: JsonSerializerOptions) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(node: Nodes.JsonNode, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo<'TValue>) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(node: Nodes.JsonNode, ?options: JsonSerializerOptions) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(element: JsonElement, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo<'TValue>) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(element: JsonElement, ?options: JsonSerializerOptions) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(document: JsonDocument, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo<'TValue>) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(document: JsonDocument, ?options: JsonSerializerOptions) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(json: string, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo<'TValue>) : 'TValue
   (+0 other overloads)
JsonSerializer.Deserialize<'TValue>(json: string, ?options: JsonSerializerOptions) : 'TValue
   (+0 other overloads)
Multiple items
type JsonSerializerOptions = new: unit -> unit + 2 overloads member AddContext<'TContext (requires default constructor and 'TContext :> JsonSerializerContext)> : unit -> unit member GetConverter: typeToConvert: Type -> JsonConverter member GetTypeInfo: ``type`` : Type -> JsonTypeInfo member MakeReadOnly: unit -> unit + 1 overload member TryGetTypeInfo: ``type`` : Type * typeInfo: byref<JsonTypeInfo> -> bool member AllowTrailingCommas: bool member Converters: IList<JsonConverter> member DefaultBufferSize: int member DefaultIgnoreCondition: JsonIgnoreCondition ...
<summary>Provides options to be used with <see cref="T:System.Text.Json.JsonSerializer" />.</summary>

--------------------
JsonSerializerOptions() : JsonSerializerOptions
JsonSerializerOptions(defaults: JsonSerializerDefaults) : JsonSerializerOptions
JsonSerializerOptions(options: JsonSerializerOptions) : JsonSerializerOptions
JsonSerializer.DeserializeAsync<'TValue>(utf8Json: System.IO.Stream, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo<'TValue>, ?cancellationToken: System.Threading.CancellationToken) : System.Threading.Tasks.ValueTask<'TValue>
JsonSerializer.DeserializeAsync<'TValue>(utf8Json: System.IO.Stream, ?options: JsonSerializerOptions, ?cancellationToken: System.Threading.CancellationToken) : System.Threading.Tasks.ValueTask<'TValue>
JsonSerializer.DeserializeAsync(utf8Json: System.IO.Stream, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo, ?cancellationToken: System.Threading.CancellationToken) : System.Threading.Tasks.ValueTask<obj>
JsonSerializer.DeserializeAsync(utf8Json: System.IO.Stream, returnType: System.Type, context: Serialization.JsonSerializerContext, ?cancellationToken: System.Threading.CancellationToken) : System.Threading.Tasks.ValueTask<obj>
JsonSerializer.DeserializeAsync(utf8Json: System.IO.Stream, returnType: System.Type, ?options: JsonSerializerOptions, ?cancellationToken: System.Threading.CancellationToken) : System.Threading.Tasks.ValueTask<obj>
JsonSerializer.DeserializeAsyncEnumerable<'TValue>(utf8Json: System.IO.Stream, jsonTypeInfo: Serialization.Metadata.JsonTypeInfo<'TValue>, ?cancellationToken: System.Threading.CancellationToken) : System.Collections.Generic.IAsyncEnumerable<'TValue>
JsonSerializer.DeserializeAsyncEnumerable<'TValue>(utf8Json: System.IO.Stream, ?options: JsonSerializerOptions, ?cancellationToken: System.Threading.CancellationToken) : System.Collections.Generic.IAsyncEnumerable<'TValue>
val options: JsonSerializerOptions

Type something to start searching.