Skip to content

Commit 6b1f244

Browse files
committed
AsyncSingleton without generic type, meant for initialization only singletons
1 parent 704ea7a commit 6b1f244

File tree

6 files changed

+670
-125
lines changed

6 files changed

+670
-125
lines changed

src/Abstract/IAsyncSingleton.cs

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Diagnostics.Contracts;
32
using System.Threading;
43
using System.Threading.Tasks;
54

@@ -9,7 +8,7 @@ namespace Soenneker.Utils.AsyncSingleton.Abstract;
98
/// An externally initializing singleton that uses double-check asynchronous locking, with optional async and sync disposal
109
/// </summary>
1110
/// <remarks>Be sure to dispose of this gracefully if using a Disposable type</remarks>
12-
public interface IAsyncSingleton<T> : IDisposable, IAsyncDisposable
11+
public interface IAsyncSingleton : IDisposable, IAsyncDisposable
1312
{
1413
/// <summary>
1514
/// Utilizes double-check async locking to guarantee there's only one instance of the object. It's lazy; it's initialized only when retrieving. <para/>
@@ -18,8 +17,7 @@ public interface IAsyncSingleton<T> : IDisposable, IAsyncDisposable
1817
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
1918
/// <exception cref="ObjectDisposedException"></exception>
2019
/// <exception cref="NullReferenceException"></exception>
21-
[Pure]
22-
ValueTask<T> Get(object[] objects);
20+
ValueTask Init(object[] objects);
2321

2422
/// <summary>
2523
/// Utilizes double-check async locking to guarantee there's only one instance of the object. It's lazy; it's initialized only when retrieving. <para/>
@@ -28,50 +26,47 @@ public interface IAsyncSingleton<T> : IDisposable, IAsyncDisposable
2826
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
2927
/// <exception cref="ObjectDisposedException"></exception>
3028
/// <exception cref="NullReferenceException"></exception>
31-
[Pure]
32-
ValueTask<T> Get(CancellationToken cancellationToken, object[] objects);
29+
ValueTask Init(CancellationToken cancellationToken, object[] objects);
3330

3431
/// <summary>
35-
/// <see cref="Get"/> should be used instead of this if possible. This method can block the calling thread! It's lazy; it's initialized only when retrieving. <para/>
32+
/// <see cref="Init(System.Threading.CancellationToken,object[])"/> should be used instead of this if possible. This method can block the calling thread! It's lazy; it's initialized only when retrieving. <para/>
3633
/// This can still be used with an async initialization func, but it will block on the func.
3734
/// </summary>
3835
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
3936
/// <exception cref="ObjectDisposedException"></exception>
4037
/// <exception cref="NullReferenceException"></exception>
41-
[Pure]
42-
T GetSync(object[] objects);
38+
void InitSync(object[] objects);
4339

4440
/// <summary>
45-
/// <see cref="Get(object[])"/> should be used instead of this if possible. This method can block the calling thread! It's lazy; it's initialized only when retrieving. <para/>
41+
/// <see cref="Init(object[])"/> should be used instead of this if possible. This method can block the calling thread! It's lazy; it's initialized only when retrieving. <para/>
4642
/// This can still be used with an async initialization func, but it will block on the func.
4743
/// </summary>
4844
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
4945
/// <exception cref="ObjectDisposedException"></exception>
5046
/// <exception cref="NullReferenceException"></exception>
51-
[Pure]
52-
T GetSync(CancellationToken cancellationToken, object[] objects);
47+
void InitSync(CancellationToken cancellationToken, object[] objects);
5348

54-
/// <see cref="SetInitialization(Func{T})"/>
55-
void SetInitialization(Func<CancellationToken, object[], ValueTask<T>> func);
49+
/// <see cref="SetInitialization(Func{object})"/>
50+
void SetInitialization(Func<CancellationToken, object[], ValueTask<object>> func);
5651

57-
/// <see cref="SetInitialization(Func{T})"/>
58-
void SetInitialization(Func<object[], ValueTask<T>> func);
52+
/// <see cref="SetInitialization(Func{object})"/>
53+
void SetInitialization(Func<object[], ValueTask<object>> func);
5954

60-
/// <see cref="SetInitialization(Func{T})"/>
61-
void SetInitialization(Func<object[], T> func);
55+
/// <see cref="SetInitialization(Func{object})"/>
56+
void SetInitialization(Func<object[], object> func);
6257

63-
/// <see cref="SetInitialization(Func{T})"/>
64-
void SetInitialization(Func<CancellationToken, object[], T> func);
58+
/// <see cref="SetInitialization(Func{object})"/>
59+
void SetInitialization(Func<CancellationToken, object[], object> func);
6560

6661
/// <summary>
6762
/// Typically not used. <para/>
6863
/// Allows for setting the initialization code outside the constructor. <para/>
6964
/// Initializing an AsyncSingleton after it's already has been set is not allowed
7065
/// </summary>
71-
void SetInitialization(Func<T> func);
66+
void SetInitialization(Func<object> func);
7267

73-
/// <see cref="SetInitialization(Func{T})"/>
74-
void SetInitialization(Func<ValueTask<T>> func);
68+
/// <see cref="SetInitialization(Func{object})"/>
69+
void SetInitialization(Func<ValueTask<object>> func);
7570

7671
/// <summary>
7772
/// If the instance is an IDisposable, Dispose will be called on the method (and DisposeAsync will not) <para/>

src/Abstract/IAsyncSingleton{T}.cs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Diagnostics.Contracts;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
namespace Soenneker.Utils.AsyncSingleton.Abstract;
7+
8+
/// <summary>
9+
/// An externally initializing singleton that uses double-check asynchronous locking, with optional async and sync disposal
10+
/// </summary>
11+
/// <remarks>Be sure to dispose of this gracefully if using a Disposable type</remarks>
12+
public interface IAsyncSingleton<T> : IDisposable, IAsyncDisposable
13+
{
14+
/// <summary>
15+
/// Utilizes double-check async locking to guarantee there's only one instance of the object. It's lazy; it's initialized only when retrieving. <para/>
16+
/// This method should be called even if the initialization func was synchronous.
17+
/// </summary>
18+
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
19+
/// <exception cref="ObjectDisposedException"></exception>
20+
/// <exception cref="NullReferenceException"></exception>
21+
[Pure]
22+
ValueTask<T> Get(object[] objects);
23+
24+
/// <summary>
25+
/// Utilizes double-check async locking to guarantee there's only one instance of the object. It's lazy; it's initialized only when retrieving. <para/>
26+
/// This method should be called even if the initialization func was synchronous.
27+
/// </summary>
28+
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
29+
/// <exception cref="ObjectDisposedException"></exception>
30+
/// <exception cref="NullReferenceException"></exception>
31+
[Pure]
32+
ValueTask<T> Get(CancellationToken cancellationToken, object[] objects);
33+
34+
/// <summary>
35+
/// <see cref="Get"/> should be used instead of this if possible. This method can block the calling thread! It's lazy; it's initialized only when retrieving. <para/>
36+
/// This can still be used with an async initialization func, but it will block on the func.
37+
/// </summary>
38+
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
39+
/// <exception cref="ObjectDisposedException"></exception>
40+
/// <exception cref="NullReferenceException"></exception>
41+
[Pure]
42+
T GetSync(object[] objects);
43+
44+
/// <summary>
45+
/// <see cref="Get(object[])"/> should be used instead of this if possible. This method can block the calling thread! It's lazy; it's initialized only when retrieving. <para/>
46+
/// This can still be used with an async initialization func, but it will block on the func.
47+
/// </summary>
48+
/// <remarks>The initialization func needs to be set before calling this, either in the ctor or via the other methods</remarks>
49+
/// <exception cref="ObjectDisposedException"></exception>
50+
/// <exception cref="NullReferenceException"></exception>
51+
[Pure]
52+
T GetSync(CancellationToken cancellationToken, object[] objects);
53+
54+
/// <see cref="SetInitialization(Func{T})"/>
55+
void SetInitialization(Func<CancellationToken, object[], ValueTask<T>> func);
56+
57+
/// <see cref="SetInitialization(Func{T})"/>
58+
void SetInitialization(Func<object[], ValueTask<T>> func);
59+
60+
/// <see cref="SetInitialization(Func{T})"/>
61+
void SetInitialization(Func<object[], T> func);
62+
63+
/// <see cref="SetInitialization(Func{T})"/>
64+
void SetInitialization(Func<CancellationToken, object[], T> func);
65+
66+
/// <summary>
67+
/// Typically not used. <para/>
68+
/// Allows for setting the initialization code outside the constructor. <para/>
69+
/// Initializing an AsyncSingleton after it's already has been set is not allowed
70+
/// </summary>
71+
void SetInitialization(Func<T> func);
72+
73+
/// <see cref="SetInitialization(Func{T})"/>
74+
void SetInitialization(Func<ValueTask<T>> func);
75+
76+
/// <summary>
77+
/// If the instance is an IDisposable, Dispose will be called on the method (and DisposeAsync will not) <para/>
78+
/// If the instance is ONLY an IAsyncDisposable and this is called, it will block while disposing. You should try to avoid this. <para/>
79+
/// </summary>
80+
/// <remarks>Disposal is not necessary unless the object's type is IDisposable/IAsyncDisposable</remarks>
81+
new void Dispose();
82+
83+
/// <summary>
84+
/// This is the preferred method of disposal. This will asynchronously dispose of the instance if the object is an IAsyncDisposable <para/>
85+
/// </summary>
86+
/// <remarks>Disposal is not necessary unless the object's type is IDisposable/IAsyncDisposable</remarks>
87+
new ValueTask DisposeAsync();
88+
}

0 commit comments

Comments
 (0)