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?
23 Replies
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker3y 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.LVTOP3y 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
Thinker3y 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 User3y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker3y 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
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker3y ago
$monad
MODiX
MODiX3y 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
Thinker3y 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.LVTOP3y ago
HmmNoted will try to create something similar first.
Thinker
Thinker3y ago
yeah sorry for maybe being a bit overwhelming
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
FroH.LVT
FroH.LVTOP3y 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 User3y ago
Message Not Public
Sign In & Join Server To View
Thinker
Thinker3y ago
(a Task is also a monad, so makes sense that it follows the same structure catsip
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
FroH.LVT
FroH.LVTOP3y ago
This is really nice though, kind of same as what Thinker said
Thinker
Thinker3y ago
yep continue ftw
FroH.LVT
FroH.LVTOP3y 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.
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
FroH.LVT
FroH.LVTOP3y ago
Thank you guys.
Accord
Accord3y ago
✅ This post has been marked as answered!
Want results from more Discord servers?
Add your server