C
C#•3y ago
FroH.LVT

Execute multiple steps with error checking [Answered]

I have multiple steps that would be executed one by one with error checking after completing each step. Eg:
void Start(){
Step1();
Step2();
....
StepN();

ResultHandling();
}
void Start(){
Step1();
Step2();
....
StepN();

ResultHandling();
}
If a step fails, all subsequent steps will not be executed and jump to ResultHandling. I had give it a try by adding a IsError variable and using it to check the execution state but it looks dirty. Are there any better way to implement this?
25 Replies
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker•3y ago
A common pattern for this (mostly in the functional world) is what's called "railway-oriented programming", in which you return from each of your steps a Result<T> type which represents either a success or an error. If you combine this with a method which chains these results, you can end up with some very readable and error-proof code. So in your case you could have something like
void Start() {
var result = Step1()
.Continue(Step2)
.Continue(Step3)
// ...
.Continue(StepN);

if (result.IsError) {
// Do error handling
}
}
void Start() {
var result = Step1()
.Continue(Step2)
.Continue(Step3)
// ...
.Continue(StepN);

if (result.IsError) {
// Do error handling
}
}
The result of each method call would encode whether it succeeded or not, in which case it will only continue if the previous result was a success, otherwise it'll just pass down the error.
FroH.LVT
FroH.LVTOP•3y ago
Thank you, I will try I'm not fan of try-catch and every step would handle and specific error on its own. So I don't use that
Thinker
Thinker•3y ago
There are also libraries for this which you could check out, notably Remora.Results and LanguageExtensions (although the latter contains a lot of other stuff)
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker•3y ago
Yep Imo it contains waaay too much for its own good It's like trying to make C# into F# without actually changing anything about the language itself
Greenthy
Greenthy•3y ago
Depending on your use case, your own implementation is also pretty easy to make but once you go down the monad path, be prepared for some headwinds 😄 it's basicly a class for which the continue returns either a new class containing the result or is empty and continue on an empty one is just another empty one without invoking the step
Thinker
Thinker•3y ago
$monad
MODiX
MODiX•3y ago
A monad is a pattern which requires a type to define three methods, here visualized as a C# interface:
interface IMonad<T>
{
// Applies a Func<T, U> to the inner value of the monad.
IMonad<U> Map<U>(Func<T, U> mapping);
// Applies a Func<T, IMonad<U>> to the inner value of the monad, and returns the result.
IMonad<U> Bind<U>(Func<T, IMonad<U>> binding);
// Returns a new monad with an inner value.
static abstract IMonad<T> Return(T value);
}
interface IMonad<T>
{
// Applies a Func<T, U> to the inner value of the monad.
IMonad<U> Map<U>(Func<T, U> mapping);
// Applies a Func<T, IMonad<U>> to the inner value of the monad, and returns the result.
IMonad<U> Bind<U>(Func<T, IMonad<U>> binding);
// Returns a new monad with an inner value.
static abstract IMonad<T> Return(T value);
}
Monads are predominantly used in functional programming, but C# natively contains a few monadic structures: * Async/await, where the inner value is the result of the task. * Nullable<T>. * IEnumerable<T>, where Select is equivalent to Map, and SelectMany is equivalent to Bind.
Thinker
Thinker•3y ago
Although really you don't need to worry about what a monad is supposed to do, it's just a useful patterns for situations like this
FroH.LVT
FroH.LVTOP•3y ago
HmmNoted will try to create something similar first.
Thinker
Thinker•3y ago
yeah sorry for maybe being a bit overwhelming
Greenthy
Greenthy•3y ago
you could ofcourse also go an easier way, making it an array of func's which return a tuple or some object you can check if it succeeded and just chain them up manually it's less fun though, and probably a lot messier code. But probably easier concept to grasp
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
FroH.LVT
FroH.LVTOP•3y ago
I wonder why your suggestion is messy. Depend on what you said, I would create something like this :
class SeriesStepInvoker{
Array<Func<T>> Steps;
void Start(){
foreach( var step in Steps){
T res = step()
if(T.IsError){
break;
}
}
ResultHandling()
}
}
class SeriesStepInvoker{
Array<Func<T>> Steps;
void Start(){
foreach( var step in Steps){
T res = step()
if(T.IsError){
break;
}
}
ResultHandling()
}
}
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker•3y ago
(a Task is also a monad, so makes sense that it follows the same structure catsip
Greenthy
Greenthy•3y ago
I guess you ment me saying it might be messier> I think it's messier cuz it's alot of code, which might end up bloated because all the logic is in the single place. You might want to pass along the results, start adding some conversions / type checking etc. If you use monads it becomes a bit more of a conceptual work than hard coded work. Which will probably result in less code and imo thus less 'messy'. I imagine especially conversions between the actual data results will get messy in your example. But if you never need any other logic in there, just looping over the steps can be the easiest as mentioned.
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
FroH.LVT
FroH.LVTOP•3y ago
This is really nice though, kind of same as what Thinker said
Thinker
Thinker•3y ago
yep continue ftw
FroH.LVT
FroH.LVTOP•3y ago
Maybe if it's in some other complex use case. My steps would return execution logs and a boolean variable to indicate if it's success. Each step has their own way to collect data which it needs. ah yeah, each step is not strongly dependent on its prior step but start in a correct order.
Greenthy
Greenthy•3y ago
you'll probably be fine with an easy loop and exiting then
FroH.LVT
FroH.LVTOP•3y ago
Thank you guys.
Accord
Accord•3y ago
✅ This post has been marked as answered!

Did you find this page helpful?