Skip to content

Commit f9a9d7c

Browse files
authored
Add Stack<T> converter example (#18358)
1 parent 0284814 commit f9a9d7c

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

docs/standard/serialization/system-text-json-converters-how-to.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ You can also write custom converters to customize or extend `System.Text.Json` w
2424
* [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties).
2525
* [Support Dictionary with non-string key](#support-dictionary-with-non-string-key).
2626
* [Support polymorphic deserialization](#support-polymorphic-deserialization).
27+
* [Support round-trip for Stack\<T>](#support-round-trip-for-stackt).
2728

2829
## Custom converter patterns
2930

@@ -172,6 +173,7 @@ The following sections provide converter samples that address some common scenar
172173
* [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties)
173174
* [Support Dictionary with non-string key](#support-dictionary-with-non-string-key)
174175
* [Support polymorphic deserialization](#support-polymorphic-deserialization)
176+
* [Support round-trip for Stack\<T>](#support-round-trip-for-stackt).
175177

176178
### Deserialize inferred types to object properties
177179

@@ -279,6 +281,26 @@ The converter can deserialize JSON that was created by using the same converter
279281

280282
The converter code in the preceding example reads and writes each property manually. An alternative is to call `Deserialize` or `Serialize` to do some of the work. For an example, see [this StackOverflow post](https://stackoverflow.com/a/59744873/12509023).
281283

284+
### Support round-trip for Stack\<T>
285+
286+
If you deserialize a JSON string into a <xref:System.Collections.Generic.Stack%601> object and then serialize that object, the contents of the stack are in reverse order. This behavior applies to the following types and interface, and user-defined types that derive from them:
287+
288+
* <xref:System.Collections.Stack>
289+
* <xref:System.Collections.Generic.Stack%601>
290+
* <xref:System.Collections.Concurrent.ConcurrentStack%601>
291+
* <xref:System.Collections.Immutable.ImmutableStack%601>
292+
* <xref:System.Collections.Immutable.IImmutableStack%601>
293+
294+
To support serialization and deserialization that retains the original order in the stack, a custom converter is required.
295+
296+
The following code shows a custom converter that enables round-tripping to and from `Stack<T>` objects:
297+
298+
[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/JsonConverterFactoryForStackOfT.cs)]
299+
300+
The following code registers the converter:
301+
302+
[!code-csharp[](~/samples/snippets/core/system-text-json/csharp/RoundtripStackOfT.cs?name=SnippetRegister)]
303+
282304
## Other custom converter samples
283305

284306
The [Migrate from Newtonsoft.Json to System.Text.Json](system-text-json-migrate-from-newtonsoft-how-to.md) article contains additional samples of custom converters.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Reflection;
5+
using System.Text.Json;
6+
using System.Text.Json.Serialization;
7+
8+
namespace SystemTextJsonSamples
9+
{
10+
public class JsonConverterFactoryForStackOfT : JsonConverterFactory
11+
{
12+
public override bool CanConvert(Type typeToConvert)
13+
{
14+
return typeToConvert.IsGenericType &&
15+
typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>);
16+
}
17+
18+
public override JsonConverter CreateConverter(
19+
Type typeToConvert, JsonSerializerOptions options)
20+
{
21+
Debug.Assert(typeToConvert.IsGenericType &&
22+
typeToConvert.GetGenericTypeDefinition() == typeof(Stack<>));
23+
24+
Type elementType = typeToConvert.GetGenericArguments()[0];
25+
26+
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
27+
typeof(JsonConverterForStackOfT<>)
28+
.MakeGenericType(new Type[] { elementType }),
29+
BindingFlags.Instance | BindingFlags.Public,
30+
binder: null,
31+
args: null,
32+
culture: null)!;
33+
34+
return converter;
35+
}
36+
}
37+
38+
public class JsonConverterForStackOfT<T> : JsonConverter<Stack<T>>
39+
{
40+
public override Stack<T> Read(
41+
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
42+
{
43+
if (reader.TokenType != JsonTokenType.StartArray || !reader.Read())
44+
{
45+
throw new JsonException();
46+
}
47+
48+
var elements = new Stack<T>();
49+
50+
while (reader.TokenType != JsonTokenType.EndArray)
51+
{
52+
elements.Push(JsonSerializer.Deserialize<T>(ref reader, options));
53+
54+
if (!reader.Read())
55+
{
56+
throw new JsonException();
57+
}
58+
}
59+
60+
return elements;
61+
}
62+
63+
public override void Write(
64+
Utf8JsonWriter writer, Stack<T> value, JsonSerializerOptions options)
65+
{
66+
writer.WriteStartArray();
67+
68+
var reversed = new Stack<T>(value);
69+
70+
foreach (T item in reversed)
71+
{
72+
JsonSerializer.Serialize(writer, item, options);
73+
}
74+
75+
writer.WriteEndArray();
76+
}
77+
}
78+
}

samples/snippets/core/system-text-json/csharp/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ static async Task Main(string[] args)
3636
Console.WriteLine("\n============================= Roundtrip enum as string\n");
3737
RoundtripEnumAsString.Run();
3838

39+
Console.WriteLine("\n============================= Roundtrip Stack<T>\n");
40+
RoundtripStackOfT.Run();
41+
3942
Console.WriteLine("\n============================= Serialize polymorphic\n");
4043
SerializePolymorphic.Run();
4144

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Collections.Immutable;
5+
using System.Text.Json;
6+
7+
namespace SystemTextJsonSamples
8+
{
9+
public class RoundtripStackOfT
10+
{
11+
public static void Run()
12+
{
13+
Console.WriteLine("Deserialize JSON string [1, 2, 3], then serialize it back to JSON.");
14+
Stack<int> stack = JsonSerializer.Deserialize<Stack<int>>("[1, 2, 3]");
15+
string serialized = JsonSerializer.Serialize(stack);
16+
Console.WriteLine($"Result is in reverse order: {serialized}");
17+
18+
Console.WriteLine("Deserialize JSON string [1, 2, 3] with custom converter, then serialize it back to JSON.");
19+
// <SnippetRegister>
20+
var options = new JsonSerializerOptions
21+
{
22+
Converters = { new JsonConverterFactoryForStackOfT() },
23+
};
24+
// </SnippetRegister>
25+
stack = JsonSerializer.Deserialize<Stack<int>>("[1, 2, 3]", options);
26+
serialized = JsonSerializer.Serialize(stack, options);
27+
Console.WriteLine($"Result is in same order: {serialized}");
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)