Skip to content

Commit 6a203a4

Browse files
committed
CSHARP-4424: Added TryRegisterClassMap method to BsonClassMap.
1 parent 470b964 commit 6a203a4

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed

src/MongoDB.Bson/Serialization/BsonClassMap.cs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,112 @@ public static void RegisterClassMap(BsonClassMap classMap)
415415
}
416416
}
417417

418+
/// <summary>
419+
/// Registers a class map if it is not already registered.
420+
/// </summary>
421+
/// <typeparam name="TClass">The class.</typeparam>
422+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
423+
public static bool TryRegisterClassMap<TClass>()
424+
{
425+
return TryRegisterClassMap(ClassMapFactory);
426+
427+
static BsonClassMap<TClass> ClassMapFactory()
428+
{
429+
var classMap = new BsonClassMap<TClass>();
430+
classMap.AutoMap();
431+
return classMap;
432+
}
433+
}
434+
435+
/// <summary>
436+
/// Registers a class map if it is not already registered.
437+
/// </summary>
438+
/// <typeparam name="TClass">The class.</typeparam>
439+
/// <param name="classMap">The class map.</param>
440+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
441+
public static bool TryRegisterClassMap<TClass>(BsonClassMap<TClass> classMap)
442+
{
443+
if (classMap == null)
444+
{
445+
throw new ArgumentNullException(nameof(classMap));
446+
}
447+
448+
return TryRegisterClassMap(ClassMapFactory);
449+
450+
BsonClassMap<TClass> ClassMapFactory()
451+
{
452+
return classMap;
453+
}
454+
}
455+
456+
/// <summary>
457+
/// Registers a class map if it is not already registered.
458+
/// </summary>
459+
/// <typeparam name="TClass">The class.</typeparam>
460+
/// <param name="classMapInitializer">The class map initializer (only called if the class map is not already registered).</param>
461+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
462+
public static bool TryRegisterClassMap<TClass>(Action<BsonClassMap<TClass>> classMapInitializer)
463+
{
464+
if (classMapInitializer == null)
465+
{
466+
throw new ArgumentNullException(nameof(classMapInitializer));
467+
}
468+
469+
return TryRegisterClassMap(ClassMapFactory);
470+
471+
BsonClassMap<TClass> ClassMapFactory()
472+
{
473+
return new BsonClassMap<TClass>(classMapInitializer);
474+
}
475+
}
476+
477+
/// <summary>
478+
/// Registers a class map if it is not already registered.
479+
/// </summary>
480+
/// <typeparam name="TClass">The class.</typeparam>
481+
/// <param name="classMapFactory">The class map factory (only called if the class map is not already registered).</param>
482+
/// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
483+
public static bool TryRegisterClassMap<TClass>(Func<BsonClassMap<TClass>> classMapFactory)
484+
{
485+
if (classMapFactory == null)
486+
{
487+
throw new ArgumentNullException(nameof(classMapFactory));
488+
}
489+
490+
BsonSerializer.ConfigLock.EnterReadLock();
491+
try
492+
{
493+
if (__classMaps.ContainsKey(typeof(TClass)))
494+
{
495+
return false;
496+
}
497+
}
498+
finally
499+
{
500+
BsonSerializer.ConfigLock.ExitReadLock();
501+
}
502+
503+
BsonSerializer.ConfigLock.EnterWriteLock();
504+
try
505+
{
506+
if (__classMaps.ContainsKey(typeof(TClass)))
507+
{
508+
return false;
509+
}
510+
else
511+
{
512+
// create a classMap for TClass and register it
513+
var classMap = classMapFactory();
514+
RegisterClassMap(classMap);
515+
return true;
516+
}
517+
}
518+
finally
519+
{
520+
BsonSerializer.ConfigLock.ExitWriteLock();
521+
}
522+
}
523+
418524
// public methods
419525
/// <summary>
420526
/// Automaps the class.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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+
using FluentAssertions;
17+
using MongoDB.Bson.Serialization;
18+
using Xunit;
19+
20+
namespace MongoDB.Bson.Tests.Jira
21+
{
22+
public class CSharp4424Tests
23+
{
24+
[Fact]
25+
public void TryRegisterClassMap_with_no_arguments_can_be_called_more_than_once()
26+
{
27+
var result = BsonClassMap.TryRegisterClassMap<C>();
28+
result.Should().BeTrue();
29+
30+
result = BsonClassMap.TryRegisterClassMap<C>();
31+
result.Should().BeFalse();
32+
}
33+
34+
[Fact]
35+
public void TryRegisterClassMap_with_classMap_can_be_called_more_than_once()
36+
{
37+
var classMap = new BsonClassMap<D>(cm => cm.AutoMap());
38+
39+
var result = BsonClassMap.TryRegisterClassMap(classMap);
40+
result.Should().BeTrue();
41+
42+
result = BsonClassMap.TryRegisterClassMap(classMap);
43+
result.Should().BeFalse();
44+
}
45+
46+
[Fact]
47+
public void TryRegisterClassMap_with_classMapInitializer_can_be_called_more_than_once()
48+
{
49+
var classMapInitializerCallCount = 0;
50+
51+
var result = BsonClassMap.TryRegisterClassMap<E>(ClassMapInitializer);
52+
result.Should().BeTrue();
53+
classMapInitializerCallCount.Should().Be(1);
54+
55+
result = BsonClassMap.TryRegisterClassMap<E>(ClassMapInitializer);
56+
result.Should().BeFalse();
57+
classMapInitializerCallCount.Should().Be(1);
58+
59+
void ClassMapInitializer(BsonClassMap<E> cm)
60+
{
61+
classMapInitializerCallCount++;
62+
cm.AutoMap();
63+
}
64+
}
65+
66+
[Fact]
67+
public void TryRegisterClassMap_with_classMapFactory_should_only_call_factory_once()
68+
{
69+
var classMapFactoryCallCount = 0;
70+
71+
var result = BsonClassMap.TryRegisterClassMap(ClassMapFactory);
72+
result.Should().BeTrue();
73+
classMapFactoryCallCount.Should().Be(1);
74+
75+
result = BsonClassMap.TryRegisterClassMap(ClassMapFactory);
76+
result.Should().BeFalse();
77+
classMapFactoryCallCount.Should().Be(1);
78+
79+
BsonClassMap<F> ClassMapFactory()
80+
{
81+
classMapFactoryCallCount++;
82+
var classMap = new BsonClassMap<F>();
83+
classMap.AutoMap();
84+
return classMap;
85+
}
86+
}
87+
88+
public class C
89+
{
90+
}
91+
92+
public class D
93+
{
94+
}
95+
96+
public class E
97+
{
98+
}
99+
100+
public class F
101+
{
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)