Skip to content

Commit 2cedfa5

Browse files
committed
CSHARP-2595: Refactor BsonClassMap to work around changes in .NET Core 3.0.
1 parent 53073cb commit 2cedfa5

File tree

2 files changed

+52
-23
lines changed

2 files changed

+52
-23
lines changed

src/MongoDB.Bson/MongoDB.Bson.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
<PackageReference Include="System.Diagnostics.Process" Version="4.1.0" />
5151
<PackageReference Include="System.Dynamic.Runtime" Version="4.0.11" />
5252
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
53+
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
5354
</ItemGroup>
5455

5556
<ItemGroup>

src/MongoDB.Bson/Serialization/BsonClassMap.cs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
using System.Linq.Expressions;
2121
using System.Reflection;
2222
using System.Runtime.CompilerServices;
23-
#if NET452
2423
using System.Runtime.Serialization;
25-
#endif
2624
using MongoDB.Bson.IO;
2725
using MongoDB.Bson.Serialization.Conventions;
2826

@@ -36,13 +34,8 @@ public class BsonClassMap
3634
// private static fields
3735
private readonly static Dictionary<Type, BsonClassMap> __classMaps = new Dictionary<Type, BsonClassMap>();
3836
private readonly static Queue<Type> __knownTypesQueue = new Queue<Type>();
39-
40-
private static readonly MethodInfo __getUninitializedObjectMethodInfo =
41-
GetFormatterServicesType()
42-
.GetTypeInfo()
43-
?.GetMethod("GetUninitializedObject", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
44-
4537
private static int __freezeNestingLevel = 0;
38+
private static readonly MethodInfo __getUninitializedObjectMethodInfo = GetGetUninitializedObjectMethodInfo();
4639

4740
// private fields
4841
private readonly Type _classType;
@@ -423,6 +416,55 @@ public static void RegisterClassMap(BsonClassMap classMap)
423416
}
424417
}
425418

419+
// private static methods
420+
private static Type GetFormatterServicesType()
421+
{
422+
#if NET452
423+
return typeof(FormatterServices);
424+
#else
425+
// TODO: once we depend on newer versions of .NET Standard we should be able to do this without reflection
426+
427+
try
428+
{
429+
// new approach which works on .NET Core 3.0
430+
var formattersAssembly = Assembly.Load(new AssemblyName("System.Runtime.Serialization.Formatters"));
431+
var formatterServicesType = formattersAssembly.GetType("System.Runtime.Serialization.FormatterServices");
432+
if (formatterServicesType != null)
433+
{
434+
return formatterServicesType;
435+
}
436+
}
437+
catch
438+
{
439+
// ignore exceptions and continue to fallback code
440+
}
441+
442+
// fallback to previous approach (which worked on older versions of .NET Core)
443+
var mscorlibAssembly = typeof(string).GetTypeInfo().Assembly;
444+
return mscorlibAssembly.GetType("System.Runtime.Serialization.FormatterServices");
445+
#endif
446+
}
447+
448+
private static MethodInfo GetGetUninitializedObjectMethodInfo()
449+
{
450+
// don't let exceptions leak out of this method because it's called from the type initializer
451+
try
452+
{
453+
var formatterServicesType = GetFormatterServicesType();
454+
if (formatterServicesType != null)
455+
{
456+
var formatterServicesTypeInfo = formatterServicesType.GetTypeInfo();
457+
return formatterServicesTypeInfo.GetMethod("GetUninitializedObject", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
458+
}
459+
}
460+
catch
461+
{
462+
// ignore exceptions
463+
}
464+
465+
return null;
466+
}
467+
426468
// public methods
427469
/// <summary>
428470
/// Automaps the class.
@@ -1303,21 +1345,7 @@ private void ThrowNotFrozenException()
13031345
var message = string.Format("Class map for {0} has been not been frozen yet.", _classType.FullName);
13041346
throw new InvalidOperationException(message);
13051347
}
1306-
1307-
private static Type GetFormatterServicesType()
1308-
{
1309-
#if NET452
1310-
return typeof(string)
1311-
.GetTypeInfo()
1312-
.Assembly
1313-
.GetType("System.Runtime.Serialization.FormatterServices");
1314-
#else
1315-
return
1316-
Assembly.Load(new AssemblyName("System.Runtime.Serialization.Formatters"))
1317-
.GetType("System.Runtime.Serialization.FormatterServices");
1318-
#endif
1319-
}
1320-
}
1348+
}
13211349

13221350
/// <summary>
13231351
/// Represents a mapping between a class and a BSON document.

0 commit comments

Comments
 (0)