BsonSerializerRegistry.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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. using System;
  16. using System.Collections.Concurrent;
  17. using System.Reflection;
  18. namespace MongoDB.Bson.Serialization
  19. {
  20. /// <summary>
  21. /// Default, global implementation of an <see cref="IBsonSerializerRegistry"/>.
  22. /// </summary>
  23. public sealed class BsonSerializerRegistry : IBsonSerializerRegistry
  24. {
  25. // private fields
  26. private readonly ConcurrentDictionary<Type, IBsonSerializer> _cache;
  27. private readonly ConcurrentStack<IBsonSerializationProvider> _serializationProviders;
  28. private readonly Func<Type, IBsonSerializer> _createSerializer;
  29. // constructors
  30. /// <summary>
  31. /// Initializes a new instance of the <see cref="BsonSerializerRegistry"/> class.
  32. /// </summary>
  33. public BsonSerializerRegistry()
  34. {
  35. _cache = new ConcurrentDictionary<Type, IBsonSerializer>();
  36. _serializationProviders = new ConcurrentStack<IBsonSerializationProvider>();
  37. _createSerializer = CreateSerializer;
  38. }
  39. // public methods
  40. /// <summary>
  41. /// Gets the serializer for the specified <paramref name="type" />.
  42. /// If none is already registered, the serialization providers will be used to create a serializer and it will be automatically registered.
  43. /// </summary>
  44. /// <param name="type">The type.</param>
  45. /// <returns>
  46. /// The serializer.
  47. /// </returns>
  48. public IBsonSerializer GetSerializer(Type type)
  49. {
  50. if (type == null)
  51. {
  52. throw new ArgumentNullException("type");
  53. }
  54. var typeInfo = type.GetTypeInfo();
  55. if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
  56. {
  57. var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type));
  58. throw new ArgumentException(message, "type");
  59. }
  60. return _cache.GetOrAdd(type, _createSerializer);
  61. }
  62. /// <summary>
  63. /// Gets the serializer for the specified <typeparamref name="T" />.
  64. /// If none is already registered, the serialization providers will be used to create a serializer and it will be automatically registered.
  65. /// </summary>
  66. /// <typeparam name="T">The value type of the serializer.</typeparam>
  67. /// <returns>
  68. /// The serializer.
  69. /// </returns>
  70. public IBsonSerializer<T> GetSerializer<T>()
  71. {
  72. return (IBsonSerializer<T>)GetSerializer(typeof(T));
  73. }
  74. /// <summary>
  75. /// Registers the serializer.
  76. /// </summary>
  77. /// <param name="type">The type.</param>
  78. /// <param name="serializer">The serializer.</param>
  79. public void RegisterSerializer(Type type, IBsonSerializer serializer)
  80. {
  81. if (type == null)
  82. {
  83. throw new ArgumentNullException("type");
  84. }
  85. if (serializer == null)
  86. {
  87. throw new ArgumentNullException("serializer");
  88. }
  89. var typeInfo = type.GetTypeInfo();
  90. if (typeof(BsonValue).GetTypeInfo().IsAssignableFrom(type))
  91. {
  92. var message = string.Format("A serializer cannot be registered for type {0} because it is a subclass of BsonValue.", BsonUtils.GetFriendlyTypeName(type));
  93. throw new BsonSerializationException(message);
  94. }
  95. if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
  96. {
  97. var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type));
  98. throw new ArgumentException(message, "type");
  99. }
  100. if (!_cache.TryAdd(type, serializer))
  101. {
  102. var message = string.Format("There is already a serializer registered for type {0}.", BsonUtils.GetFriendlyTypeName(type));
  103. throw new BsonSerializationException(message);
  104. }
  105. }
  106. /// <summary>
  107. /// Registers the serialization provider. This behaves like a stack, so the
  108. /// last provider registered is the first provider consulted.
  109. /// </summary>
  110. /// <param name="serializationProvider">The serialization provider.</param>
  111. public void RegisterSerializationProvider(IBsonSerializationProvider serializationProvider)
  112. {
  113. if (serializationProvider == null)
  114. {
  115. throw new ArgumentNullException("serializationProvider");
  116. }
  117. _serializationProviders.Push(serializationProvider);
  118. }
  119. // private methods
  120. private IBsonSerializer CreateSerializer(Type type)
  121. {
  122. foreach (var serializationProvider in _serializationProviders)
  123. {
  124. IBsonSerializer serializer;
  125. var registryAwareSerializationProvider = serializationProvider as IRegistryAwareBsonSerializationProvider;
  126. if (registryAwareSerializationProvider != null)
  127. {
  128. serializer = registryAwareSerializationProvider.GetSerializer(type, this);
  129. }
  130. else
  131. {
  132. serializer = serializationProvider.GetSerializer(type);
  133. }
  134. if (serializer != null)
  135. {
  136. return serializer;
  137. }
  138. }
  139. var message = string.Format("No serializer found for type {0}.", type.FullName);
  140. throw new BsonSerializationException(message);
  141. }
  142. }
  143. }