forked from NetTopologySuite/GeoAPI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGeometryServiceProvider.cs
More file actions
150 lines (133 loc) · 5.7 KB
/
GeometryServiceProvider.cs
File metadata and controls
150 lines (133 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
#if COMPAT_BOOTSTRAP_USING_REFLECTION && HAS_SYSTEM_APPDOMAIN_GETASSEMBLIES && HAS_SYSTEM_REFLECTION_ASSEMBLY_GETEXPORTEDTYPES
using System.Reflection;
#endif
namespace GeoAPI
{
/// <summary>
/// Static class that provides access to a <see cref="IGeometryServices"/> class.
/// </summary>
public static class GeometryServiceProvider
{
private static volatile IGeometryServices s_instance;
/// <summary>
/// Make sure only one thread runs <see cref="InitializeInstance"/> at a time.
/// </summary>
private static readonly object s_autoInitLock = new object();
/// <summary>
/// Make sure that anyone who directly sets <see cref="Instance"/>, including the automatic
/// initializer, behaves consistently, regarding <see cref="s_instanceSetDirectly"/> and the
/// semantics of <see cref="SetInstanceIfNotAlreadySetDirectly"/>.
/// </summary>
private static readonly object s_explicitInitLock = new object();
/// <summary>
/// Indicates whether or not <see cref="s_instance"/> has been set directly (i.e., outside
/// of the reflection-based initializer).
/// </summary>
private static bool s_instanceSetDirectly = false;
/// <summary>
/// Gets or sets the <see cref="IGeometryServices"/> instance.
/// </summary>
public static IGeometryServices Instance
{
get => s_instance ?? InitializeInstance();
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
lock (s_explicitInitLock)
{
s_instance = value;
s_instanceSetDirectly = true;
}
}
}
/// <summary>
/// Sets <see cref="Instance"/> to the given value, unless it has already been set directly.
/// Both this method and the property's setter itself count as setting it "directly".
/// </summary>
/// <param name="instance">
/// The new value to put into <see cref="Instance"/> if it hasn't already been set directly.
/// </param>
/// <returns>
/// <c>true</c> if <see cref="Instance"/> was set, <c>false</c> otherwise.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="instance"/> is <see langword="null"/>.
/// </exception>
public static bool SetInstanceIfNotAlreadySetDirectly(IGeometryServices instance)
{
if (instance == null)
{
throw new ArgumentNullException(nameof(instance));
}
lock (s_explicitInitLock)
{
if (s_instanceSetDirectly)
{
// someone has already set the value directly before.
return false;
}
s_instance = instance;
// calling this method counts.
s_instanceSetDirectly = true;
return true;
}
}
private static IGeometryServices InitializeInstance()
{
#if COMPAT_BOOTSTRAP_USING_REFLECTION && HAS_SYSTEM_APPDOMAIN_GETASSEMBLIES && HAS_SYSTEM_REFLECTION_ASSEMBLY_GETEXPORTEDTYPES
lock (s_autoInitLock)
{
// see if someone has already set it while we were waiting for the lock.
var instance = s_instance;
if (instance != null) return instance;
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.GlobalAssemblyCache && assembly.CodeBase == Assembly.GetExecutingAssembly().CodeBase)
continue;
var assemblyType = assembly.GetType().FullName;
if (assemblyType == "System.Reflection.Emit.AssemblyBuilder" ||
assemblyType == "System.Reflection.Emit.InternalAssemblyBuilder")
continue;
Type[] types;
try
{
types = assembly.GetExportedTypes();
}
catch (ReflectionTypeLoadException ex)
{
types = ex.Types;
}
catch (Exception)
{
continue;
}
var requiredType = typeof(IGeometryServices);
foreach (var type in types)
{
if (type.IsNotPublic || type.IsInterface || type.IsAbstract || !requiredType.IsAssignableFrom(type))
continue;
foreach (var constructor in type.GetConstructors())
if (constructor.IsPublic && constructor.GetParameters().Length == 0)
{
instance = (IGeometryServices)Activator.CreateInstance(type);
lock (s_explicitInitLock)
{
if (!s_instanceSetDirectly)
{
s_instance = instance;
}
return s_instance;
}
}
}
}
}
#endif
throw new InvalidOperationException("Cannot use GeometryServiceProvider without an assigned IGeometryServices class");
}
}
}