Reputation: 2329
In a piece of C# that I am writing at the moment I need to handle several methods with the same signature in the same way. Also there might be more of these methods in the future. Instead of repeating the same kind of logic over and over I thought up the following:
private delegate bool cleanStep(BuildData bd, out String strFailure);
List<cleanStep> steps = new List<cleanStep>();
steps.Add(WriteReadme);
steps.Add(DeleteFiles);
steps.Add(TFSHelper.DeleteLabel);
steps.Add(TFSHelper.DeleteBuild);
List<cleanStep>.Enumerator enumerator = steps.GetEnumerator();
bool result = true;
while (result && enumerator.MoveNext())
{
result = enumerator.Current.Invoke(build, out strFailure);
if (!result)
{
logger.Write(LogTypes.Error, strFailure);
}
}
I think this has some nice features but it also feels a bit over enginered and obfuscating.
Can you thank of a better a way of doing this ?
btw:
Thanks.
Upvotes: 1
Views: 245
Reputation: 5161
I would return an Exception object instead of a string. Since exceptions often have a global policy, I would write some Exception extensions. Now you get:
static Exception Run( this IEnumerable<Step> steps) {
return
steps
.FirstOrDefault( (step) => step( build ) != null )
.LogIfFailure(); //or .ThrowIfFailure()
}
The extensions:
public static class ExceptionExtensions {
private static logger = new Logger();
public static Exception LogIfFailure( this Exception e ) {
if( e != null )
logger.Write( e.Message );
return e;
}
public static Exception ShowDialogIfFailure( this Exception e ) {
if( e != null )
MessageBox.Show( e.Message );
return e;
}
public static void ThrowIfFailure( this Exception e ) {
if( e != null )
Throw( e );
}
}
Upvotes: 0
Reputation: 1062530
Re obfuscated - well foreach
with break might be clearer (plus it'll Dispose()
the enumerator, which you aren't doing).
Actually, a "params cleanStep[] targets" might help:
static bool RunTargets(params cleanStep[] targets)
{
// detail as per Jon's post
}
then you can call:
bool foo = RunTargets(WriteReadme, DeleteFiles,
TFSHelper.DeleteLabel, TFSHelper.DeleteBuild);
Upvotes: 0
Reputation: 43254
Your solution is both straight foward and easy to understand. I can see no reason to do it another way :)
The only thing I'd suggest is to replace your iterator with a foreach loop and break on an error.
Upvotes: 2
Reputation: 1499750
Why not use a foreach loop and just break? (I've renamed cleanStep
to CleanStep
here for conventionality - I suggest you do the same.)
foreach(CleanStep step in steps)
{
string failureText;
if (!step(build, out failureText))
{
logger.Write(LogTypes.Error, strFailure);
break;
}
}
Note that this also obeys the contract of IEnumerator<T>
where your current code doesn't - foreach
automatically calls Dispose
, and IEnumerator<T>
implements IDisposable
. It won't be an issue in this case, but with iterator blocks, disposal is used to execute finally
blocks.
Upvotes: 9