diff --git a/src/Stateless/ParameterConversion.cs b/src/Stateless/ParameterConversion.cs index ff28c4f7..07c42b95 100644 --- a/src/Stateless/ParameterConversion.cs +++ b/src/Stateless/ParameterConversion.cs @@ -23,6 +23,38 @@ public static object Unpack(object[] args, Type argType, int index) return arg; } + + public static bool TryUnpack(object[] args, Type argType, int index, out object result) + { + if (args == null) + { + result = null; + return false; + } + + if (args.Length == 0) + { + result = null; + return false; + } + + if (args.Length <= index) + { + result = null; + return false; + } + + var arg = args[index]; + + if (arg != null && !argType.IsAssignableFrom(arg.GetType())) + { + result = null; + return false; + } + + result = arg; + return true; + } public static TArg Unpack(object[] args, int index) { @@ -30,6 +62,25 @@ public static TArg Unpack(object[] args, int index) return (TArg)Unpack(args, typeof(TArg), index); } + + public static bool TryUnpack(object[] args, int index, out TArg result) + { + if (args.Length == 0) + { + result = default; + return true; + } + + object rawResult; + if (!TryUnpack(args, typeof(TArg), index, out rawResult)) + { + result = default; + return false; + } + + result = (TArg) rawResult; + return true; + } public static void Validate(object[] args, Type[] expected) { diff --git a/src/Stateless/TransitionGuard.cs b/src/Stateless/TransitionGuard.cs index 2b9dbf2b..9fe57dad 100644 --- a/src/Stateless/TransitionGuard.cs +++ b/src/Stateless/TransitionGuard.cs @@ -16,22 +16,24 @@ internal class TransitionGuard public static Func ToPackedGuard(Func guard) { - return args => guard(ParameterConversion.Unpack(args, 0)); + return args => ParameterConversion.TryUnpack(args, 0, out var arg) && guard(arg); } public static Func ToPackedGuard(Func guard) { - return args => guard( - ParameterConversion.Unpack(args, 0), - ParameterConversion.Unpack(args, 1)); + return args => + ParameterConversion.TryUnpack(args, 0, out var arg0) + && ParameterConversion.TryUnpack(args, 1, out var arg1) + && guard(arg0, arg1); } public static Func ToPackedGuard(Func guard) { - return args => guard( - ParameterConversion.Unpack(args, 0), - ParameterConversion.Unpack(args, 1), - ParameterConversion.Unpack(args, 2)); + return args => + ParameterConversion.TryUnpack(args, 0, out var arg0) + && ParameterConversion.TryUnpack(args, 1, out var arg1) + && ParameterConversion.TryUnpack(args, 2, out var arg2) + && guard(arg0, arg1, arg2); } public static Tuple, string>[] ToPackedGuards(Tuple, string>[] guards)