Improve wait and try utilities

This commit is contained in:
Stone_Red
2025-11-25 19:19:02 +01:00
parent 864604b36c
commit 7184b6b15c
3 changed files with 37 additions and 25 deletions
+7 -7
View File
@@ -36,7 +36,7 @@ public class WaitTests
await Task.Delay(200); await Task.Delay(200);
flag = true; flag = true;
}); });
Wait.Until(() => flag, TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(2)); Wait.Until(() => flag, TimeSpan.FromMilliseconds(50));
Assert.IsTrue(flag); Assert.IsTrue(flag);
} }
@@ -87,7 +87,7 @@ public class WaitTests
handler(42); handler(42);
}); });
} }
int result = await Wait.WaitForEventAsync((Action<Action<int>>)subscribe, TimeSpan.FromSeconds(2)); int result = await Wait.ForEventAsync((Action<Action<int>>)subscribe, TimeSpan.FromSeconds(2));
Assert.AreEqual(42, result); Assert.AreEqual(42, result);
} }
@@ -100,7 +100,7 @@ public class WaitTests
} }
_ = await Assert.ThrowsExactlyAsync<TimeoutException>(async () => _ = await Assert.ThrowsExactlyAsync<TimeoutException>(async () =>
{ {
_ = await Wait.WaitForEventAsync((Action<Action<int>>)subscribe, TimeSpan.FromMilliseconds(200)); _ = await Wait.ForEventAsync((Action<Action<int>>)subscribe, TimeSpan.FromMilliseconds(200));
}); });
} }
@@ -115,7 +115,7 @@ public class WaitTests
handler(); handler();
}); });
} }
Wait.WaitForEvent(subscribe, TimeSpan.FromSeconds(2)); Wait.ForEvent(subscribe, TimeSpan.FromSeconds(2));
} }
[TestMethod] [TestMethod]
@@ -127,7 +127,7 @@ public class WaitTests
} }
_ = Assert.ThrowsExactly<TimeoutException>(() => _ = Assert.ThrowsExactly<TimeoutException>(() =>
{ {
Wait.WaitForEvent(subscribe, TimeSpan.FromMilliseconds(200)); Wait.ForEvent(subscribe, TimeSpan.FromMilliseconds(200));
}); });
} }
@@ -142,7 +142,7 @@ public class WaitTests
handler("hello"); handler("hello");
}); });
} }
string result = Wait.WaitForEvent((Action<Action<string>>)subscribe, TimeSpan.FromSeconds(2)); string result = Wait.ForEvent((Action<Action<string>>)subscribe, TimeSpan.FromSeconds(2));
Assert.AreEqual("hello", result); Assert.AreEqual("hello", result);
} }
@@ -155,7 +155,7 @@ public class WaitTests
} }
_ = Assert.ThrowsExactly<TimeoutException>(() => _ = Assert.ThrowsExactly<TimeoutException>(() =>
{ {
_ = Wait.WaitForEvent((Action<Action<string>>)subscribe, TimeSpan.FromMilliseconds(200)); _ = Wait.ForEvent((Action<Action<string>>)subscribe, TimeSpan.FromMilliseconds(200));
}); });
} }
} }
+1 -1
View File
@@ -124,7 +124,7 @@ public static class Try
catch (Exception ex) catch (Exception ex)
{ {
lastException = ex; lastException = ex;
System.Threading.Thread.Sleep(delay.Value); Thread.Sleep(delay.Value);
} }
} }
throw new InvalidOperationException($"Failed after {maxRetries} attempts.", lastException); throw new InvalidOperationException($"Failed after {maxRetries} attempts.", lastException);
+29 -17
View File
@@ -1,4 +1,6 @@
namespace CuteUtils.Misc; using System.Diagnostics;
namespace CuteUtils.Misc;
/// <summary> /// <summary>
/// Provides utility methods for waiting on conditions or events with optional timeouts and intervals. /// Provides utility methods for waiting on conditions or events with optional timeouts and intervals.
@@ -16,15 +18,20 @@ public static class Wait
{ {
timeout ??= TimeSpan.MaxValue; timeout ??= TimeSpan.MaxValue;
interval ??= TimeSpan.FromMilliseconds(100); interval ??= TimeSpan.FromMilliseconds(100);
DateTime endTime = DateTime.UtcNow.Add(timeout.Value);
while (!condition() && DateTime.UtcNow < endTime) Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed < timeout.Value)
{ {
if (condition())
{
return;
}
await Task.Delay(interval.Value); await Task.Delay(interval.Value);
} }
if (!condition())
{ throw new TimeoutException("The condition was not met within the specified timeout.");
throw new TimeoutException("The condition was not met within the specified timeout.");
}
} }
/// <summary> /// <summary>
@@ -38,15 +45,20 @@ public static class Wait
{ {
timeout ??= TimeSpan.MaxValue; timeout ??= TimeSpan.MaxValue;
interval ??= TimeSpan.FromMilliseconds(100); interval ??= TimeSpan.FromMilliseconds(100);
DateTime endTime = DateTime.UtcNow.Add(timeout.Value);
while (!condition() && DateTime.UtcNow < endTime) Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed < timeout.Value)
{ {
System.Threading.Thread.Sleep(interval.Value); if (condition())
} {
if (!condition()) return;
{ }
throw new TimeoutException("The condition was not met within the specified timeout.");
Thread.Sleep(interval.Value);
} }
throw new TimeoutException("The condition was not met within the specified timeout.");
} }
/// <summary> /// <summary>
@@ -88,7 +100,7 @@ public static class Wait
/// <typeparam name="T">The type of the event argument.</typeparam> /// <typeparam name="T">The type of the event argument.</typeparam>
/// <returns>A task that completes with the event argument when the event is raised.</returns> /// <returns>A task that completes with the event argument when the event is raised.</returns>
/// <exception cref="TimeoutException">Thrown if the event is not raised within the timeout.</exception> /// <exception cref="TimeoutException">Thrown if the event is not raised within the timeout.</exception>
public static async Task<T> WaitForEventAsync<T>(Action<Action<T>> subscribe, TimeSpan? timeout = null) public static async Task<T> ForEventAsync<T>(Action<Action<T>> subscribe, TimeSpan? timeout = null)
{ {
timeout ??= TimeSpan.MaxValue; timeout ??= TimeSpan.MaxValue;
@@ -121,7 +133,7 @@ public static class Wait
/// <param name="subscribe">An action that subscribes a handler to the event.</param> /// <param name="subscribe">An action that subscribes a handler to the event.</param>
/// <param name="timeout">The maximum time to wait. Defaults to infinite.</param> /// <param name="timeout">The maximum time to wait. Defaults to infinite.</param>
/// <exception cref="TimeoutException">Thrown if the event is not raised within the timeout.</exception> /// <exception cref="TimeoutException">Thrown if the event is not raised within the timeout.</exception>
public static void WaitForEvent(Action<Action> subscribe, TimeSpan? timeout = null) public static void ForEvent(Action<Action> subscribe, TimeSpan? timeout = null)
{ {
timeout ??= TimeSpan.MaxValue; timeout ??= TimeSpan.MaxValue;
TaskCompletionSource tcs = new TaskCompletionSource(); TaskCompletionSource tcs = new TaskCompletionSource();
@@ -152,7 +164,7 @@ public static class Wait
/// <typeparam name="T">The type of the event argument.</typeparam> /// <typeparam name="T">The type of the event argument.</typeparam>
/// <returns>The event argument when the event is raised.</returns> /// <returns>The event argument when the event is raised.</returns>
/// <exception cref="TimeoutException">Thrown if the event is not raised within the timeout.</exception> /// <exception cref="TimeoutException">Thrown if the event is not raised within the timeout.</exception>
public static T WaitForEvent<T>(Action<Action<T>> subscribe, TimeSpan? timeout = null) public static T ForEvent<T>(Action<Action<T>> subscribe, TimeSpan? timeout = null)
{ {
timeout ??= TimeSpan.MaxValue; timeout ??= TimeSpan.MaxValue;
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>(); TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();