Skip to content

Commit 064fc63

Browse files
authored
CSHARP-3494: Fix discriminator for generic types (#1685)
1 parent cacbcf8 commit 064fc63

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

src/MongoDB.Bson/Serialization/BsonClassMap.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ public void Reset()
10571057
_creatorMaps.Clear();
10581058
_creator = null;
10591059
_declaredMemberMaps = new List<BsonMemberMap>();
1060-
_discriminator = _classType.Name;
1060+
_discriminator = BsonUtils.GetFriendlyTypeName(_classType);
10611061
_discriminatorIsRequired = false;
10621062
_extraElementsMemberMap = null;
10631063
_idMemberMap = null;

tests/MongoDB.Bson.Tests/Jira/CSharp515Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public S(IList<T> list)
4545
}
4646

4747
private static readonly string __discriminatorAssemblyName = "MongoDB.Bson.Tests";
48-
private string _jsonTemplate = ("{ '_id' : 1, 'R' : #V, 'S' : #V, 'RS' : { '_t' : 'S`1', '_v' : #V }, 'OR' : { '_t' : 'System.Collections.ObjectModel.ReadOnlyCollection`1[System.Int32]', '_v' : #V }, 'OS' : { '_t' : 'MongoDB.Bson.Tests.Jira.CSharp515.CSharp515Tests+S`1[System.Int32], " + __discriminatorAssemblyName + "', '_v' : #V } }").Replace("'", "\"");
48+
private string _jsonTemplate = ("{ '_id' : 1, 'R' : #V, 'S' : #V, 'RS' : { '_t' : 'S<Int32>', '_v' : #V }, 'OR' : { '_t' : 'System.Collections.ObjectModel.ReadOnlyCollection`1[System.Int32]', '_v' : #V }, 'OS' : { '_t' : 'MongoDB.Bson.Tests.Jira.CSharp515.CSharp515Tests+S`1[System.Int32], " + __discriminatorAssemblyName + "', '_v' : #V } }").Replace("'", "\"");
4949

5050
[Fact]
5151
public void TestNull()

tests/MongoDB.Bson.Tests/Serialization/Serializers/DiscriminatorTests.cs

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

16+
using System.Collections.Generic;
1617
using System.Linq;
18+
using FluentAssertions;
1719
using MongoDB.Bson.Serialization;
1820
using MongoDB.Bson.Serialization.Attributes;
1921
using MongoDB.Bson.TestHelpers;
@@ -65,6 +67,79 @@ private class H : G
6567
{
6668
}
6769

70+
// BaseDocument and derived classes are used for tests with generic types
71+
// It's necessary to specify the derived specific types with BsonKnownTypes for the deserialization to work.
72+
[BsonKnownTypes(typeof(DerivedDocument<int>))]
73+
[BsonKnownTypes(typeof(DerivedDocument<List<Dictionary<string, int>>>))]
74+
[BsonKnownTypes(typeof(DerivedDocumentDouble<int, string>))]
75+
abstract class BaseDocument;
76+
77+
class DerivedDocument<T> : BaseDocument
78+
{
79+
[BsonId]
80+
public int Id { get; set; }
81+
82+
public T Value { get; set; }
83+
}
84+
85+
class DerivedDocumentDouble<T1, T2> : BaseDocument
86+
{
87+
[BsonId]
88+
public int Id { get; set; }
89+
90+
public T1 Value1 { get; set; }
91+
92+
public T2 Value2 { get; set; }
93+
}
94+
95+
[Fact]
96+
public void TestDeserializeGenericType()
97+
{
98+
var serialized = """{ "_t" : "DerivedDocument<Int32>", "_id" : 1, "Value" : 42 }""";
99+
var rehydrated = BsonSerializer.Deserialize<BaseDocument>(serialized);
100+
rehydrated.Should().BeOfType<DerivedDocument<int>>();
101+
}
102+
103+
[Fact]
104+
public void TestDeserializeGenericTypeWithNestedType()
105+
{
106+
var serialized = """{ "_t" : "DerivedDocument<List<Dictionary<String, Int32>>>", "_id" : 1, "Value" : [{ "key" : 1 }] }""";
107+
var rehydrated = BsonSerializer.Deserialize<BaseDocument>(serialized);
108+
rehydrated.Should().BeOfType<DerivedDocument<List<Dictionary<string, int>>>>();
109+
}
110+
111+
[Fact]
112+
public void TestDeserializeGenericTypeWithTwoTypes()
113+
{
114+
var serialized = """{ "_t" : "DerivedDocumentDouble<Int32, String>", "_id" : 1, "Value1" : 42, "Value2" : "hello" }""";
115+
var rehydrated = BsonSerializer.Deserialize<BaseDocument>(serialized);
116+
rehydrated.Should().BeOfType<DerivedDocumentDouble<int,string>>();
117+
}
118+
119+
[Fact]
120+
public void TestSerializeGenericType()
121+
{
122+
var document = new DerivedDocument<int> { Id = 1, Value = 42 };
123+
var serialized = document.ToJson(typeof(BaseDocument));
124+
serialized.Should().Be("""{ "_t" : "DerivedDocument<Int32>", "_id" : 1, "Value" : 42 }""");
125+
}
126+
127+
[Fact]
128+
public void TestSerializeGenericTypeWithNestedType()
129+
{
130+
var document = new DerivedDocument<List<Dictionary<string, int>>> { Id = 1, Value = [new() { { "key", 1 } }] };
131+
var serialized = document.ToJson(typeof(BaseDocument));
132+
serialized.Should().Be("""{ "_t" : "DerivedDocument<List<Dictionary<String, Int32>>>", "_id" : 1, "Value" : [{ "key" : 1 }] }""");
133+
}
134+
135+
[Fact]
136+
public void TestSerializeGenericTypeWithTwoTypes()
137+
{
138+
var document = new DerivedDocumentDouble<int, string> { Id = 1, Value1 = 42, Value2 = "hello"};
139+
var serialized = document.ToJson(typeof(BaseDocument));
140+
serialized.Should().Be("""{ "_t" : "DerivedDocumentDouble<Int32, String>", "_id" : 1, "Value1" : 42, "Value2" : "hello" }""");
141+
}
142+
68143
[Fact]
69144
public void TestSerializeObjectasObject()
70145
{

0 commit comments

Comments
 (0)