Skip to content
This repository was archived by the owner on Jun 22, 2023. It is now read-only.

Commit 4615d9a

Browse files
authored
Fix #41. (#42)
* Fix #41. Add a method to set GeometryServiceProvider.Instance if nobody else has yet.
1 parent 5020f3c commit 4615d9a

File tree

1 file changed

+79
-6
lines changed

1 file changed

+79
-6
lines changed

src/GeoAPI/GeometryServiceProvider.cs

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
#if COMPAT_BOOTSTRAP_USING_REFLECTION && HAS_SYSTEM_APPDOMAIN_GETASSEMBLIES && HAS_SYSTEM_REFLECTION_ASSEMBLY_GETEXPORTEDTYPES
33
using System.Reflection;
4-
using System.Threading;
54
#endif
65

76
namespace GeoAPI
@@ -12,22 +11,88 @@ namespace GeoAPI
1211
public static class GeometryServiceProvider
1312
{
1413
private static volatile IGeometryServices s_instance;
15-
private static readonly object s_lock = new object();
14+
15+
/// <summary>
16+
/// Make sure only one thread runs <see cref="InitializeInstance"/> at a time.
17+
/// </summary>
18+
private static readonly object s_autoInitLock = new object();
19+
20+
/// <summary>
21+
/// Make sure that anyone who directly sets <see cref="Instance"/>, including the automatic
22+
/// initializer, behaves consistently, regarding <see cref="s_instanceSetDirectly"/> and the
23+
/// semantics of <see cref="SetInstanceIfNotAlreadySetDirectly"/>.
24+
/// </summary>
25+
private static readonly object s_explicitInitLock = new object();
26+
27+
/// <summary>
28+
/// Indicates whether or not <see cref="s_instance"/> has been set directly (i.e., outside
29+
/// of the reflection-based initializer).
30+
/// </summary>
31+
private static bool s_instanceSetDirectly = false;
1632

1733
/// <summary>
1834
/// Gets or sets the <see cref="IGeometryServices"/> instance.
1935
/// </summary>
2036
public static IGeometryServices Instance
2137
{
2238
get => s_instance ?? InitializeInstance();
23-
set => s_instance = value ?? throw new ArgumentNullException(nameof(value));
39+
set
40+
{
41+
if (value == null)
42+
{
43+
throw new ArgumentNullException(nameof(value));
44+
}
45+
46+
lock (s_explicitInitLock)
47+
{
48+
s_instance = value;
49+
s_instanceSetDirectly = true;
50+
}
51+
}
52+
}
53+
54+
/// <summary>
55+
/// Sets <see cref="Instance"/> to the given value, unless it has already been set directly.
56+
/// Both this method and the property's setter itself count as setting it "directly".
57+
/// </summary>
58+
/// <param name="instance">
59+
/// The new value to put into <see cref="Instance"/> if it hasn't already been set directly.
60+
/// </param>
61+
/// <returns>
62+
/// <c>true</c> if <see cref="Instance"/> was set, <c>false</c> otherwise.
63+
/// </returns>
64+
/// <exception cref="ArgumentNullException">
65+
/// Thrown when <paramref name="instance"/> is <see langword="null"/>.
66+
/// </exception>
67+
public static bool SetInstanceIfNotAlreadySetDirectly(IGeometryServices instance)
68+
{
69+
if (instance == null)
70+
{
71+
throw new ArgumentNullException(nameof(instance));
72+
}
73+
74+
lock (s_explicitInitLock)
75+
{
76+
if (s_instanceSetDirectly)
77+
{
78+
// someone has already set the value directly before.
79+
return false;
80+
}
81+
82+
s_instance = instance;
83+
84+
// calling this method counts.
85+
s_instanceSetDirectly = true;
86+
return true;
87+
}
2488
}
2589

2690
private static IGeometryServices InitializeInstance()
2791
{
2892
#if COMPAT_BOOTSTRAP_USING_REFLECTION && HAS_SYSTEM_APPDOMAIN_GETASSEMBLIES && HAS_SYSTEM_REFLECTION_ASSEMBLY_GETEXPORTEDTYPES
29-
lock (s_lock)
93+
lock (s_autoInitLock)
3094
{
95+
// see if someone has already set it while we were waiting for the lock.
3196
var instance = s_instance;
3297
if (instance != null) return instance;
3398
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
@@ -64,8 +129,16 @@ private static IGeometryServices InitializeInstance()
64129
foreach (var constructor in type.GetConstructors())
65130
if (constructor.IsPublic && constructor.GetParameters().Length == 0)
66131
{
67-
Interlocked.CompareExchange(ref s_instance, (IGeometryServices)Activator.CreateInstance(type), null);
68-
return s_instance;
132+
instance = (IGeometryServices)Activator.CreateInstance(type);
133+
lock (s_explicitInitLock)
134+
{
135+
if (!s_instanceSetDirectly)
136+
{
137+
s_instance = instance;
138+
}
139+
140+
return s_instance;
141+
}
69142
}
70143
}
71144
}

0 commit comments

Comments
 (0)