Skip to content

Commit 4d63c8e

Browse files
James Hadwenrstam
authored andcommitted
CSHARP-1447: Allow serialization of generic IDictionary implementations with non-public constructors when serializing to an interface definition
1 parent 71d7373 commit 4d63c8e

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

src/MongoDB.Bson.Tests/Serialization/Serializers/DictionaryGenericSerializerTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
*/
1515

1616
using System;
17+
using System.Collections;
1718
using System.Collections.Generic;
19+
using System.Collections.ObjectModel;
1820
using System.IO;
1921
using System.Linq;
2022
using System.Text;
@@ -43,6 +45,19 @@ public class T
4345
public SortedList<object, object> SL { get; set; }
4446
}
4547

48+
public class RO<TKey, TValue> : ReadOnlyDictionary<TKey, TValue>
49+
{
50+
private RO(IDictionary<TKey, TValue> dictionary)
51+
: base(dictionary)
52+
{
53+
}
54+
55+
public static RO<TKey, TValue> ConstructorReplacement(IDictionary<TKey, TValue> dictionary)
56+
{
57+
return new RO<TKey, TValue>(dictionary);
58+
}
59+
}
60+
4661
[Test]
4762
public void TestNull()
4863
{
@@ -388,6 +403,28 @@ public void TestMixedPrimitiveTypesWithMixedKeys()
388403
Assert.Throws<BsonSerializationException>(() => obj.ToBson());
389404
}
390405

406+
[Test]
407+
public void TestImmutablePrivateConstructorDictionaryImplementation()
408+
{
409+
var d = new Dictionary<object, object> { { "A", new C { P = "x" } } };
410+
var id = RO<object, object>.ConstructorReplacement(d);
411+
var sd = CreateSortedDictionary(d);
412+
var sl = CreateSortedList(d);
413+
var obj = new T { D = d, ID = id, SD = sd, SL = sl };
414+
var json = obj.ToJson();
415+
var rep = "{ 'A' : { '_t' : 'DictionaryGenericSerializers.C', 'P' : 'x' } }";
416+
var expected = "{ 'D' : #R, 'ID' : #R, 'SD' : #R, 'SL' : #R }".Replace("#R", rep).Replace("'", "\"");
417+
Assert.AreEqual(expected, json);
418+
419+
var bson = obj.ToBson();
420+
var rehydrated = BsonSerializer.Deserialize<T>(bson);
421+
Assert.IsInstanceOf<Dictionary<object, object>>(rehydrated.D);
422+
Assert.IsInstanceOf<Dictionary<object, object>>(rehydrated.ID);
423+
Assert.IsInstanceOf<SortedDictionary<object, object>>(rehydrated.SD);
424+
Assert.IsInstanceOf<SortedList<object, object>>(rehydrated.SL);
425+
Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));
426+
}
427+
391428
private SortedDictionary<object, object> CreateSortedDictionary(Dictionary<object, object> d)
392429
{
393430
var sd = new SortedDictionary<object, object>();

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* limitations under the License.
1414
*/
1515

16+
using System;
1617
using System.Collections;
1718
using System.Collections.Generic;
1819
using MongoDB.Bson.Serialization.Options;
@@ -164,7 +165,7 @@ public class DictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>
164165
DictionarySerializerBase<TDictionary, TKey, TValue>,
165166
IChildSerializerConfigurable,
166167
IDictionaryRepresentationConfigurable<DictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>>
167-
where TDictionary : class, IDictionary<TKey, TValue>, new()
168+
where TDictionary : class, IDictionary<TKey, TValue>
168169
{
169170
/// <summary>
170171
/// Initializes a new instance of the <see cref="DictionaryInterfaceImplementerSerializer{TDictionary, TKey, TValue}"/> class.
@@ -271,7 +272,7 @@ public DictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithV
271272
/// <returns>The instance.</returns>
272273
protected override TDictionary CreateInstance()
273274
{
274-
return new TDictionary();
275+
return Activator.CreateInstance<TDictionary>();
275276
}
276277

277278
// explicit interface implementations

0 commit comments

Comments
 (0)