diff --git a/src/MongoDB.Bson/Serialization/BsonClassMap.cs b/src/MongoDB.Bson/Serialization/BsonClassMap.cs
index 87239a33bf5..2781d218d6b 100644
--- a/src/MongoDB.Bson/Serialization/BsonClassMap.cs
+++ b/src/MongoDB.Bson/Serialization/BsonClassMap.cs
@@ -1323,10 +1323,25 @@ internal IDiscriminatorConvention GetDiscriminatorConvention()
var discriminatorConvention = _discriminatorConvention;
if (discriminatorConvention == null)
{
- // it's possible but harmless for multiple threads to do the discriminator convention lookukp at the same time
+ // it's possible but harmless for multiple threads to do the discriminator convention lookup at the same time
discriminatorConvention = LookupDiscriminatorConvention();
_discriminatorConvention = discriminatorConvention;
+
+ if (discriminatorConvention != null)
+ {
+ var conflictingMemberMap = _allMemberMaps.FirstOrDefault(memberMap => memberMap.ElementName == discriminatorConvention.ElementName);
+
+ if (conflictingMemberMap != null)
+ {
+ var fieldOrProperty = conflictingMemberMap.MemberInfo is FieldInfo ? "field" : "property";
+
+ throw new BsonSerializationException(
+ $"The discriminator element name cannot be {discriminatorConvention.ElementName} " +
+ $"because it is already being used by the {fieldOrProperty} {conflictingMemberMap.MemberName} of type {_classType.FullName}");
+ }
+ }
}
+
return discriminatorConvention;
IDiscriminatorConvention LookupDiscriminatorConvention()
diff --git a/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
index ca4d2cbc117..55148561676 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
@@ -39,14 +39,15 @@ public abstract class StandardDiscriminatorConvention : IDiscriminatorConvention
/// The element name.
protected StandardDiscriminatorConvention(string elementName)
{
- if (elementName == null)
+ if (string.IsNullOrEmpty(elementName))
{
- throw new ArgumentNullException("elementName");
+ throw new ArgumentException("Element names cannot be null or empty.", nameof(elementName));
}
if (elementName.IndexOf('\0') != -1)
{
- throw new ArgumentException("Element names cannot contain nulls.", "elementName");
+ throw new ArgumentException("Element names cannot contain nulls.", nameof(elementName));
}
+
_elementName = elementName;
}
diff --git a/tests/MongoDB.Bson.Tests/Serialization/Conventions/StandardDiscriminatorConventionTests.cs b/tests/MongoDB.Bson.Tests/Serialization/Conventions/StandardDiscriminatorConventionTests.cs
index f1d633bd724..25fabd6b479 100644
--- a/tests/MongoDB.Bson.Tests/Serialization/Conventions/StandardDiscriminatorConventionTests.cs
+++ b/tests/MongoDB.Bson.Tests/Serialization/Conventions/StandardDiscriminatorConventionTests.cs
@@ -31,7 +31,7 @@ public void TestConstructorThrowsWhenElementNameContainsNulls()
[Fact]
public void TestConstructorThrowsWhenElementNameIsNull()
{
- Assert.Throws(() => new ScalarDiscriminatorConvention(null));
+ Assert.Throws(() => new ScalarDiscriminatorConvention(null));
}
[Fact]
diff --git a/tests/MongoDB.Driver.Tests/Jira/CSharp4040Tests.cs b/tests/MongoDB.Driver.Tests/Jira/CSharp4040Tests.cs
new file mode 100644
index 00000000000..7858491fd0a
--- /dev/null
+++ b/tests/MongoDB.Driver.Tests/Jira/CSharp4040Tests.cs
@@ -0,0 +1,47 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using FluentAssertions;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Attributes;
+using Xunit;
+
+namespace MongoDB.Driver.Tests.Jira
+{
+ public class CSharp4040Tests
+ {
+ private class BaseDocument
+ {
+ [BsonId] public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
+
+ [BsonElement("_t")]
+ public string Field1 { get; set; }
+ }
+
+ private class DerivedDocument : BaseDocument {}
+
+ [Fact]
+ public void BsonClassMapSerializer_serialization_when_using_field_with_same_element_name_as_discriminator_should_throw()
+ {
+ var obj = new DerivedDocument { Field1 = "field1" };
+
+ var recordedException = Record.Exception(() => obj.ToJson(typeof(BaseDocument)));
+ recordedException.Should().NotBeNull();
+ recordedException.Should().BeOfType();
+ recordedException.Message.Should().Be("The discriminator element name cannot be _t because it is already being used" +
+ " by the property Field1 of type MongoDB.Driver.Tests.Jira.CSharp4040Tests+DerivedDocument");
+ }
+ }
+}