diff --git a/src/LuYao.Common/Guard.cs b/src/LuYao.Common/Guard.cs
new file mode 100644
index 0000000..9d6e208
--- /dev/null
+++ b/src/LuYao.Common/Guard.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Threading.Tasks;
+
+namespace LuYao;
+
+///
+/// Provides guarded execution helpers to reduce try/catch boilerplate
+/// while keeping behavior observable and configurable.
+///
+public static class Guard
+{
+ ///
+ /// Executes an action with guarded exception handling.
+ ///
+ /// The action to execute.
+ /// An optional callback invoked when a handled exception is caught.
+ /// An optional predicate to determine whether an exception should be handled.
+ /// If , rethrows handled exceptions after invoking .
+ /// when execution succeeds; otherwise for handled exceptions.
+ public static bool TryRun(Action action, Action? onError = null, Func? when = null, bool rethrow = false)
+ {
+ if (action == null) throw new ArgumentNullException(nameof(action));
+
+ try
+ {
+ action();
+ return true;
+ }
+ catch (Exception ex) when (CanHandle(ex, when))
+ {
+ onError?.Invoke(ex);
+ if (rethrow) throw;
+ return false;
+ }
+ }
+
+ ///
+ /// Executes an asynchronous action with guarded exception handling.
+ ///
+ /// The asynchronous action to execute.
+ /// An optional callback invoked when a handled exception is caught.
+ /// An optional predicate to determine whether an exception should be handled.
+ /// If , rethrows handled exceptions after invoking .
+ /// A task that returns when execution succeeds; otherwise for handled exceptions.
+ public static async Task TryRunAsync(Func action, Action? onError = null, Func? when = null, bool rethrow = false)
+ {
+ try
+ {
+ await action();
+ return true;
+ }
+ catch (Exception ex) when (CanHandle(ex, when))
+ {
+ onError?.Invoke(ex);
+ if (rethrow) throw;
+ return false;
+ }
+ }
+
+ ///
+ /// Executes a function and returns its result, or a fallback value when a handled exception occurs.
+ ///
+ /// The result type.
+ /// The function to execute.
+ /// The fallback value returned when a handled exception occurs.
+ /// An optional callback invoked when a handled exception is caught.
+ /// An optional predicate to determine whether an exception should be handled.
+ /// If , rethrows handled exceptions after invoking .
+ /// The function result when successful; otherwise for handled exceptions.
+ public static T TryGet(Func func, T fallback = default!, Action? onError = null, Func? when = null, bool rethrow = false)
+ {
+ if (func == null) throw new ArgumentNullException(nameof(func));
+
+ try
+ {
+ return func();
+ }
+ catch (Exception ex) when (CanHandle(ex, when))
+ {
+ onError?.Invoke(ex);
+ if (rethrow) throw;
+ return fallback;
+ }
+ }
+
+ ///
+ /// Executes an asynchronous function and returns its result,
+ /// or a fallback value when a handled exception occurs.
+ ///
+ /// The result type.
+ /// The asynchronous function to execute.
+ /// The fallback value returned when a handled exception occurs.
+ /// An optional callback invoked when a handled exception is caught.
+ /// An optional predicate to determine whether an exception should be handled.
+ /// If , rethrows handled exceptions after invoking .
+ /// A task that returns the function result when successful; otherwise for handled exceptions.
+ public static async Task TryGetAsync(Func> func, T fallback = default!, Action? onError = null, Func? when = null, bool rethrow = false)
+ {
+ if (func == null) throw new ArgumentNullException(nameof(func));
+
+ try
+ {
+ return await func();
+ }
+ catch (Exception ex) when (CanHandle(ex, when))
+ {
+ onError?.Invoke(ex);
+ if (rethrow) throw;
+ return fallback;
+ }
+ }
+
+ private static bool CanHandle(Exception ex, Func? when)
+ {
+ if (IsCritical(ex)) return false;
+ if (when == null) return true;
+ return when(ex);
+ }
+
+ private static bool IsCritical(Exception ex)
+ {
+ return ex is OperationCanceledException
+ || ex is OutOfMemoryException
+ || ex is StackOverflowException
+ || ex is AccessViolationException
+ || ex is AppDomainUnloadedException
+ || ex is BadImageFormatException
+ || ex is CannotUnloadAppDomainException
+ || ex is InvalidProgramException;
+ }
+}
\ No newline at end of file
diff --git a/tests/LuYao.Common.UnitTests/GuardTests.cs b/tests/LuYao.Common.UnitTests/GuardTests.cs
new file mode 100644
index 0000000..18cf131
--- /dev/null
+++ b/tests/LuYao.Common.UnitTests/GuardTests.cs
@@ -0,0 +1,95 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace LuYao;
+
+[TestClass]
+public class GuardTests
+{
+ [TestMethod]
+ public void TryRun_WhenActionSucceeds_ReturnsTrue()
+ {
+ bool result = Guard.TryRun(() => { });
+
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public void TryRun_WhenActionThrows_ReturnsFalseAndInvokesOnError()
+ {
+ Exception? captured = null;
+
+ bool result = Guard.TryRun(() => throw new InvalidOperationException("boom"), ex => captured = ex);
+
+ Assert.IsFalse(result);
+ Assert.IsNotNull(captured);
+ Assert.IsInstanceOfType(captured);
+ }
+
+ [TestMethod]
+ public void TryRun_WhenRethrowIsTrue_RethrowsHandledException()
+ {
+ Assert.Throws(() =>
+ Guard.TryRun(() => throw new InvalidOperationException("boom"), rethrow: true));
+ }
+
+ [TestMethod]
+ public void TryRun_WhenFilterReturnsFalse_DoesNotHandleException()
+ {
+ Assert.Throws(() =>
+ Guard.TryRun(() => throw new InvalidOperationException("boom"), when: _ => false));
+ }
+
+ [TestMethod]
+ public void TryRun_WhenOperationCanceledExceptionThrown_DoesNotHandleException()
+ {
+ Assert.Throws(() =>
+ Guard.TryRun(() => throw new OperationCanceledException()));
+ }
+
+ [TestMethod]
+ public void TryGet_WhenFuncThrows_ReturnsFallback()
+ {
+ int value = Guard.TryGet(() => throw new InvalidOperationException("boom"), fallback: 42);
+
+ Assert.AreEqual(42, value);
+ }
+
+ [TestMethod]
+ public async Task TryRunAsync_WhenActionThrows_ReturnsFalseAndInvokesOnError()
+ {
+ Exception? captured = null;
+
+ bool result = await Guard.TryRunAsync(
+ async () =>
+ {
+ await Task.Yield();
+ throw new InvalidOperationException("boom");
+ },
+ ex => captured = ex);
+
+ Assert.IsFalse(result);
+ Assert.IsNotNull(captured);
+ Assert.IsInstanceOfType(captured);
+ }
+
+ [TestMethod]
+ public async Task TryRunAsync_WhenOperationCanceledExceptionThrown_DoesNotHandleException()
+ {
+ await Assert.ThrowsAsync(async () =>
+ await Guard.TryRunAsync(async () =>
+ {
+ await Task.Yield();
+ throw new OperationCanceledException();
+ }));
+ }
+
+ [TestMethod]
+ public async Task TryGetAsync_WhenFuncThrows_ReturnsFallback()
+ {
+ int value = await Guard.TryGetAsync(
+ () => Task.FromException(new InvalidOperationException("boom")),
+ fallback: 64);
+
+ Assert.AreEqual(64, value);
+ }
+}
\ No newline at end of file