Skip to content

Commit 528cd61

Browse files
authored
CSHARP-5335: New serializers for immutable collections (#1508)
1 parent 31028d0 commit 528cd61

22 files changed

+1389
-13
lines changed

src/MongoDB.Bson/Serialization/CollectionsSerializationProvider.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
using System;
1717
using System.Collections;
1818
using System.Collections.Generic;
19+
#if NET6_0_OR_GREATER
20+
using System.Collections.Immutable;
21+
#endif
1922
using System.Collections.ObjectModel;
2023
using System.Dynamic;
2124
using System.Linq;
@@ -43,7 +46,17 @@ static CollectionsSerializationProvider()
4346
{ typeof(ReadOnlyCollection<>), typeof(ReadOnlyCollectionSerializer<>) },
4447
{ typeof(Stack<>), typeof(StackSerializer<>) },
4548
{ typeof(Memory<>), typeof(MemorySerializer<>) },
46-
{ typeof(ReadOnlyMemory<>), typeof(ReadonlyMemorySerializer<>) }
49+
{ typeof(ReadOnlyMemory<>), typeof(ReadonlyMemorySerializer<>) },
50+
#if NET6_0_OR_GREATER
51+
{ typeof(ImmutableArray<>), typeof(ImmutableArraySerializer<>) },
52+
{ typeof(ImmutableList<>), typeof(ImmutableListSerializer<>) },
53+
{ typeof(ImmutableHashSet<>), typeof(ImmutableHashSetSerializer<>) },
54+
{ typeof(ImmutableSortedSet<>), typeof(ImmutableSortedSetSerializer<>) },
55+
{ typeof(ImmutableDictionary<,>), typeof(ImmutableDictionarySerializer<,>) },
56+
{ typeof(ImmutableSortedDictionary<,>), typeof(ImmutableSortedDictionarySerializer<,>) },
57+
{ typeof(ImmutableQueue<>), typeof(ImmutableQueueSerializer<>) },
58+
{ typeof(ImmutableStack<>), typeof(ImmutableStackSerializer<>) }
59+
#endif
4760
};
4861
}
4962

src/MongoDB.Bson/Serialization/Serializers/EnumerableInterfaceImplementerSerializer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace MongoDB.Bson.Serialization.Serializers
2727
public sealed class EnumerableInterfaceImplementerSerializer<TValue> :
2828
EnumerableInterfaceImplementerSerializerBase<TValue>,
2929
IChildSerializerConfigurable
30-
where TValue : class, IList, new()
30+
where TValue : IEnumerable, new()
3131
{
3232
// constructors
3333
/// <summary>
@@ -96,7 +96,7 @@ IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer
9696
public sealed class EnumerableInterfaceImplementerSerializer<TValue, TItem> :
9797
EnumerableInterfaceImplementerSerializerBase<TValue, TItem>,
9898
IChildSerializerConfigurable
99-
where TValue : class, IEnumerable<TItem>
99+
where TValue : IEnumerable<TItem>
100100
{
101101
// constructors
102102
/// <summary>

src/MongoDB.Bson/Serialization/Serializers/EnumerableInterfaceImplementerSerializerBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace MongoDB.Bson.Serialization.Serializers
2222
/// Represents a serializer for enumerable values.
2323
/// </summary>
2424
/// <typeparam name="TValue">The type of the value.</typeparam>
25-
public abstract class EnumerableInterfaceImplementerSerializerBase<TValue> : EnumerableSerializerBase<TValue>, IBsonArraySerializer where TValue : class, IEnumerable
25+
public abstract class EnumerableInterfaceImplementerSerializerBase<TValue> : EnumerableSerializerBase<TValue> where TValue : IEnumerable
2626
{
2727
// constructors
2828
/// <summary>
@@ -87,7 +87,7 @@ protected override TValue FinalizeResult(object accumulator)
8787
/// </summary>
8888
/// <typeparam name="TValue">The type of the value.</typeparam>
8989
/// <typeparam name="TItem">The type of the items.</typeparam>
90-
public abstract class EnumerableInterfaceImplementerSerializerBase<TValue, TItem> : EnumerableSerializerBase<TValue, TItem>, IBsonArraySerializer where TValue : class, IEnumerable<TItem>
90+
public abstract class EnumerableInterfaceImplementerSerializerBase<TValue, TItem> : EnumerableSerializerBase<TValue, TItem> where TValue : IEnumerable<TItem>
9191
{
9292
// constructors
9393
/// <summary>

src/MongoDB.Bson/Serialization/Serializers/EnumerableSerializerBase.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace MongoDB.Bson.Serialization.Serializers
2424
/// Represents a base serializer for enumerable values.
2525
/// </summary>
2626
/// <typeparam name="TValue">The type of the value.</typeparam>
27-
public abstract class EnumerableSerializerBase<TValue> : SerializerBase<TValue>, IBsonArraySerializer where TValue : class, IEnumerable
27+
public abstract class EnumerableSerializerBase<TValue> : SerializerBase<TValue>, IBsonArraySerializer where TValue : IEnumerable
2828
{
2929
// private fields
3030
private readonly IDiscriminatorConvention _discriminatorConvention = new ScalarDiscriminatorConvention("_t");
@@ -93,8 +93,12 @@ public override TValue Deserialize(BsonDeserializationContext context, BsonDeser
9393
switch (bsonType)
9494
{
9595
case BsonType.Null:
96+
if (typeof(TValue).IsValueType)
97+
{
98+
throw new FormatException($"Cannot deserialize a null value into a value type (type: {BsonUtils.GetFriendlyTypeName(typeof(TValue))}).");
99+
}
96100
bsonReader.ReadNull();
97-
return null;
101+
return default;
98102

99103
case BsonType.Array:
100104
bsonReader.ReadStartArray();
@@ -219,7 +223,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
219223
/// </summary>
220224
/// <typeparam name="TValue">The type of the value.</typeparam>
221225
/// <typeparam name="TItem">The type of the items.</typeparam>
222-
public abstract class EnumerableSerializerBase<TValue, TItem> : SerializerBase<TValue>, IBsonArraySerializer where TValue : class, IEnumerable<TItem>
226+
public abstract class EnumerableSerializerBase<TValue, TItem> : SerializerBase<TValue>, IBsonArraySerializer where TValue : IEnumerable<TItem>
223227
{
224228
// private fields
225229
private readonly IDiscriminatorConvention _discriminatorConvention = new ScalarDiscriminatorConvention("_t");
@@ -289,8 +293,12 @@ public override TValue Deserialize(BsonDeserializationContext context, BsonDeser
289293
switch (bsonType)
290294
{
291295
case BsonType.Null:
296+
if (typeof(TValue).IsValueType)
297+
{
298+
throw new FormatException($"Cannot deserialize a null value into a value type (type: {BsonUtils.GetFriendlyTypeName(typeof(TValue))}).");
299+
}
292300
bsonReader.ReadNull();
293-
return null;
301+
return default;
294302

295303
case BsonType.Array:
296304
bsonReader.ReadStartArray();
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#if NET6_0_OR_GREATER
17+
using System.Collections.Immutable;
18+
19+
namespace MongoDB.Bson.Serialization.Serializers
20+
{
21+
/// <summary>
22+
/// Represents a serializer for ImmutableArrays.
23+
/// </summary>
24+
/// <typeparam name="T">The type of element stored by the collection.</typeparam>
25+
public class ImmutableArraySerializer<T>: EnumerableInterfaceImplementerSerializerBase<ImmutableArray<T>, T>
26+
{
27+
/// <inheritdoc/>
28+
protected override object CreateAccumulator()
29+
{
30+
return ImmutableArray.CreateBuilder<T>();
31+
}
32+
33+
/// <inheritdoc/>
34+
protected override ImmutableArray<T> FinalizeResult(object accumulator)
35+
{
36+
return ((ImmutableArray<T>.Builder)accumulator).ToImmutable();
37+
}
38+
}
39+
}
40+
#endif
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#if NET6_0_OR_GREATER
17+
using System.Collections.Generic;
18+
using System.Collections.Immutable;
19+
20+
namespace MongoDB.Bson.Serialization.Serializers
21+
{
22+
/// <summary>
23+
/// Represents a serializer for ImmutableDictionaries.
24+
/// </summary>
25+
/// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
26+
/// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
27+
public class ImmutableDictionarySerializer<TKey, TValue>: DictionaryInterfaceImplementerSerializer<ImmutableDictionary<TKey, TValue>, TKey, TValue>
28+
{
29+
/// <inheritdoc/>
30+
protected override ICollection<KeyValuePair<TKey, TValue>> CreateAccumulator()
31+
{
32+
return ImmutableDictionary.CreateBuilder<TKey, TValue>();
33+
}
34+
35+
/// <inheritdoc/>
36+
protected override ImmutableDictionary<TKey, TValue> FinalizeAccumulator(ICollection<KeyValuePair<TKey, TValue>> accumulator)
37+
{
38+
return ((ImmutableDictionary<TKey, TValue>.Builder)accumulator).ToImmutable();
39+
}
40+
}
41+
}
42+
#endif
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#if NET6_0_OR_GREATER
17+
using System.Collections.Immutable;
18+
19+
namespace MongoDB.Bson.Serialization.Serializers
20+
{
21+
/// <summary>
22+
/// Represents a serializer for ImmutableHashSets.
23+
/// </summary>
24+
/// <typeparam name="T">The type of element stored by the collection.</typeparam>
25+
public class ImmutableHashSetSerializer<T>: EnumerableInterfaceImplementerSerializerBase<ImmutableHashSet<T>, T>
26+
{
27+
/// <inheritdoc/>
28+
protected override object CreateAccumulator()
29+
{
30+
return ImmutableHashSet.CreateBuilder<T>();
31+
}
32+
33+
/// <inheritdoc/>
34+
protected override ImmutableHashSet<T> FinalizeResult(object accumulator)
35+
{
36+
return ((ImmutableHashSet<T>.Builder)accumulator).ToImmutable();
37+
}
38+
}
39+
}
40+
#endif
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#if NET6_0_OR_GREATER
17+
using System.Collections.Immutable;
18+
19+
namespace MongoDB.Bson.Serialization.Serializers
20+
{
21+
/// <summary>
22+
/// Represents a serializer for ImmutableLists.
23+
/// </summary>
24+
/// <typeparam name="T">The type of element stored by the collection.</typeparam>
25+
public class ImmutableListSerializer<T>: EnumerableInterfaceImplementerSerializerBase<ImmutableList<T>, T>
26+
{
27+
/// <inheritdoc/>
28+
protected override object CreateAccumulator()
29+
{
30+
return ImmutableList.CreateBuilder<T>();
31+
}
32+
33+
/// <inheritdoc/>
34+
protected override ImmutableList<T> FinalizeResult(object accumulator)
35+
{
36+
return ((ImmutableList<T>.Builder)accumulator).ToImmutable();
37+
}
38+
}
39+
}
40+
#endif
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#if NET6_0_OR_GREATER
17+
using System.Collections.Generic;
18+
using System.Collections.Immutable;
19+
20+
namespace MongoDB.Bson.Serialization.Serializers
21+
{
22+
/// <summary>
23+
/// Represents a serializer for ImmutableQueues.
24+
/// </summary>
25+
/// <typeparam name="T">The type of element stored by the collection.</typeparam>
26+
public class ImmutableQueueSerializer<T>: EnumerableInterfaceImplementerSerializerBase<ImmutableQueue<T>, T>
27+
{
28+
/// <inheritdoc/>
29+
protected override object CreateAccumulator()
30+
{
31+
return new List<T>();
32+
}
33+
34+
/// <inheritdoc/>
35+
protected override ImmutableQueue<T> FinalizeResult(object accumulator)
36+
{
37+
return ImmutableQueue.CreateRange((List<T>)accumulator);
38+
}
39+
}
40+
}
41+
#endif
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#if NET6_0_OR_GREATER
17+
using System.Collections.Generic;
18+
using System.Collections.Immutable;
19+
20+
namespace MongoDB.Bson.Serialization.Serializers
21+
{
22+
/// <summary>
23+
/// Represents a serializer for ImmutableSortedDictionaries.
24+
/// </summary>
25+
/// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
26+
/// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
27+
public class ImmutableSortedDictionarySerializer<TKey, TValue>: DictionaryInterfaceImplementerSerializer<ImmutableSortedDictionary<TKey, TValue>, TKey, TValue>
28+
{
29+
/// <inheritdoc/>
30+
protected override ICollection<KeyValuePair<TKey, TValue>> CreateAccumulator()
31+
{
32+
return ImmutableSortedDictionary.CreateBuilder<TKey, TValue>();
33+
}
34+
35+
/// <inheritdoc/>
36+
protected override ImmutableSortedDictionary<TKey, TValue> FinalizeAccumulator(ICollection<KeyValuePair<TKey, TValue>> accumulator)
37+
{
38+
return ((ImmutableSortedDictionary<TKey, TValue>.Builder)accumulator).ToImmutable();
39+
}
40+
}
41+
}
42+
#endif

0 commit comments

Comments
 (0)