Skip to content

Commit c136c1a

Browse files
committed
Added additional delegate helpers
1 parent d546418 commit c136c1a

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

src/DotNext.Tests/DelegateHelpersTests.cs

+45
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Globalization;
22
using System.Linq.Expressions;
33
using System.Reflection;
4+
using System.Runtime.CompilerServices;
45

56
namespace DotNext;
67

@@ -498,4 +499,48 @@ public static void Identity()
498499
{
499500
Equal(42, Func.Identity<int>().Invoke(42));
500501
}
502+
503+
[Fact]
504+
public static void ToAsync1()
505+
{
506+
var func = new Action(static () => { }).ToAsync();
507+
True(func.Invoke(new(canceled: false)).IsCompletedSuccessfully);
508+
True(func.Invoke(new(canceled: true)).IsCanceled);
509+
510+
func = new Action(static () => throw new Exception()).ToAsync();
511+
True(func.Invoke(new(canceled: false)).IsFaulted);
512+
}
513+
514+
[Fact]
515+
public static void ToAsync2()
516+
{
517+
var func = new Action<int>(static _ => { }).ToAsync();
518+
True(func.Invoke(42, new(canceled: false)).IsCompletedSuccessfully);
519+
True(func.Invoke(42, new(canceled: true)).IsCanceled);
520+
521+
func = new Action<int>(static _ => throw new Exception()).ToAsync();
522+
True(func.Invoke(42, new(canceled: false)).IsFaulted);
523+
}
524+
525+
[Fact]
526+
public static void HideReturnValue1()
527+
{
528+
var box = new StrongBox<int>();
529+
var action = new Func<int>(ChangeValue).HideReturnValue();
530+
action.Invoke();
531+
Equal(42, box.Value);
532+
533+
int ChangeValue() => box.Value = 42;
534+
}
535+
536+
[Fact]
537+
public static void HideReturnValue2()
538+
{
539+
var box = new StrongBox<int>();
540+
var action = new Func<int, int>(ChangeValue).HideReturnValue();
541+
action.Invoke(42);
542+
Equal(42, box.Value);
543+
544+
int ChangeValue(int value) => box.Value = value;
545+
}
501546
}

src/DotNext/DelegateHelpers.cs

+108
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,112 @@ public static EventHandler<T> Contravariant<TBase, T>(this EventHandler<TBase> h
8888
public static TDelegate ChangeType<TDelegate>(this Delegate d)
8989
where TDelegate : Delegate
9090
=> d is TDelegate ? Unsafe.As<TDelegate>(d) : ChangeType<TDelegate, EmptyTargetRewriter>(d, new EmptyTargetRewriter());
91+
92+
/// <summary>
93+
/// Converts action to async delegate.
94+
/// </summary>
95+
/// <param name="action">Synchronous action.</param>
96+
/// <typeparam name="T">The type of the argument to be passed to the action.</typeparam>
97+
/// <returns>The asynchronous function that wraps <paramref name="action"/>.</returns>
98+
/// <exception cref="ArgumentNullException"><paramref name="action"/> is <see langword="null"/>.</exception>
99+
public static Func<T, CancellationToken, ValueTask> ToAsync<T>(this Action<T> action)
100+
{
101+
ArgumentNullException.ThrowIfNull(action);
102+
103+
return action.Invoke;
104+
}
105+
106+
private static ValueTask Invoke<T>(this Action<T> action, T arg, CancellationToken token)
107+
{
108+
ValueTask task;
109+
if (token.IsCancellationRequested)
110+
{
111+
task = ValueTask.FromCanceled(token);
112+
}
113+
else
114+
{
115+
task = ValueTask.CompletedTask;
116+
try
117+
{
118+
action.Invoke(arg);
119+
}
120+
catch (Exception e)
121+
{
122+
task = ValueTask.FromException(e);
123+
}
124+
}
125+
126+
return task;
127+
}
128+
129+
/// <summary>
130+
/// Converts action to async delegate.
131+
/// </summary>
132+
/// <param name="action">Synchronous action.</param>
133+
/// <returns>The asynchronous function that wraps <paramref name="action"/>.</returns>
134+
/// <exception cref="ArgumentNullException"><paramref name="action"/> is <see langword="null"/>.</exception>
135+
public static Func<CancellationToken, ValueTask> ToAsync(this Action action)
136+
{
137+
ArgumentNullException.ThrowIfNull(action);
138+
139+
return action.Invoke;
140+
}
141+
142+
private static ValueTask Invoke(this Action action, CancellationToken token)
143+
{
144+
ValueTask task;
145+
if (token.IsCancellationRequested)
146+
{
147+
task = ValueTask.FromCanceled(token);
148+
}
149+
else
150+
{
151+
task = ValueTask.CompletedTask;
152+
try
153+
{
154+
action.Invoke();
155+
}
156+
catch (Exception e)
157+
{
158+
task = ValueTask.FromException(e);
159+
}
160+
}
161+
162+
return task;
163+
}
164+
165+
/// <summary>
166+
/// Creates a delegate that hides the return value.
167+
/// </summary>
168+
/// <param name="func">The function.</param>
169+
/// <typeparam name="TResult">The type of the result.</typeparam>
170+
/// <returns>The action that invokes the same method as <paramref name="func"/>.</returns>
171+
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception>
172+
public static Action HideReturnValue<TResult>(this Func<TResult> func)
173+
{
174+
ArgumentNullException.ThrowIfNull(func);
175+
176+
return func.InvokeNoReturn;
177+
}
178+
179+
private static void InvokeNoReturn<TResult>(this Func<TResult> func)
180+
=> func.Invoke();
181+
182+
/// <summary>
183+
/// Creates a delegate that hides the return value.
184+
/// </summary>
185+
/// <param name="func">The function.</param>
186+
/// <typeparam name="TResult">The type of the result.</typeparam>
187+
/// <typeparam name="T">The type of the argument to be passed to the action.</typeparam>
188+
/// <returns>The action that invokes the same method as <paramref name="func"/>.</returns>
189+
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception>
190+
public static Action<T> HideReturnValue<T, TResult>(this Func<T, TResult> func)
191+
{
192+
ArgumentNullException.ThrowIfNull(func);
193+
194+
return func.InvokeNoReturn;
195+
}
196+
197+
private static void InvokeNoReturn<T, TResult>(this Func<T, TResult> func, T arg)
198+
=> func.Invoke(arg);
91199
}

0 commit comments

Comments
 (0)