How to prevent the arrowhead anti-pattern - c#

I'm a bit confused about how to best refactor my code into something more readable.
Consider this piece of code:
var foo = getfoo();
if(foo!=null)
{
var bar = getbar(foo);
if(bar!=null)
{
var moo = getmoo(bar);
if(moo!=null)
{
var cow = getcow(moo);
...
}
}
}
return;
As you can see, lots of nested if blocks, needed because each nested if is dependent on the previous values.
Now I was wondering how to make my code a bit cleaner in this regard.
Some options I have thought of myself would be to:
return after each if clause, meaning I'd have multiple places where I leave my method
throw ArgumentNullExceptions, after which I'd catch them in the end and place the return statement in my finally clause (or outside the try/catch block)
work with a label and goto:
Most of these options seem a bit "dirty" to me, so I was wondering if there was a good way to clean up this mess that I've created.

I'd go for the multiple return statements. This makes the code easy to read and understand.
Don't use goto for obvious reasons.
Don't use exceptions because the check you are doing isn't exceptional, it's something you can expect so you should just take that into account. Programming against exceptions is also an anti-pattern.

Consider inverting the null checks to:
var foo = getfoo();
if (foo == null)
{
return;
}
var bar = getbar(foo);
if (bar == null)
{
return;
}
...etc

You can chain expressions. An assignment returns the assigned value, so you can check its result. Also, you can use the assigned variable in the next expression.
As soon as an expression returns false, the others are not longer executed, because the entire expression would return false already (because of the and operation).
So, something like this should work:
Foo foo; Bar bar; Moo moo; Cow cow;
if( (foo = getfoo()) != null &&
(bar = getbar(foo)) != null &&
(moo = getmoo(bar)) != null &&
(cow = getcow(moo)) != null )
{
..
}

This is one of few scenarios where it is perfectly acceptable (if not desirable) to use goto.
In functions like this, there will often be resources that are allocated or state changes that are made mid-way which need to be undone before the function exits.
The usual problem with return-based solutions (e.g., rexcfnghk's and Gerrie Schenck's) is that you need to remember to undo those state changes before every return. This leads to code duplication and opens the door to subtle errors, especially in larger functions. Do not do this.
CERT actually recommends a structural approach based on goto.
In particular, note their example code taken from copy_process in kernel/fork.c of the Linux kernel. A simplified version of the concept is as follows:
if (!modify_state1(true))
goto cleanup_none;
if (!modify_state2(true))
goto cleanup_state1;
if (!modify_state3(true))
goto cleanup_state2;
// ...
cleanup_state3:
modify_state3(false);
cleanup_state2:
modify_state2(false);
cleanup_state1:
modify_state1(false);
cleanup_none:
return;
Essentially, this is just a more readable version of the "arrowhead" code that doesn't use unnecessary indentation or duplicate code. This concept can easily be extended to whatever best suits your situation.
As a final note, especially regarding CERT's first compliant example, I just want to add that, whenever possible, it is simpler to design your code so that the cleanup can be handled all at once. That way, you can write code like this:
FILE *f1 = null;
FILE *f2 = null;
void *mem = null;
if ((f1 = fopen(FILE1, "r")) == null)
goto cleanup;
if ((f2 = fopen(FILE2, "r")) == null)
goto cleanup;
if ((mem = malloc(OBJSIZE)) == null)
goto cleanup;
// ...
cleanup:
free(mem); // These functions gracefully exit given null input
close(f2);
close(f1);
return;

First your suggestion (return after each if clause) is quite a good way out:
// Contract (first check all the input)
var foo = getfoo();
if (Object.ReferenceEquals(null, foo))
return; // <- Or throw exception, put assert etc.
var bar = getbar(foo);
if (Object.ReferenceEquals(null, bar))
return; // <- Or throw exception, put assert etc.
var moo = getmoo(bar);
if (Object.ReferenceEquals(null, moo))
return; // <- Or throw exception, put assert etc.
// Routine: all instances (foo, bar, moo) are correct (not null) and we can work with them
...
The second possibility (in your very case) is to slightly modify your getbar() as well as getmoo() functions such that they return null on null input, so you'll have
var foo = getfoo();
var bar = getbar(foo); // return null if foo is null
var moo = getmoo(bar); // return null if bar is null
if ((foo == null) || (bar == null) || (moo == null))
return; // <- Or throw exception, put assert(s) etc.
// Routine: all instances (foo, bar, moo) are correct (not null)
...
The third possibility is that in complicated cases you can use Null Object Desing Patteren
http://en.wikipedia.org/wiki/Null_Object_pattern

Do it old-school:
var foo;
var bar;
var moo;
var cow;
var failed = false;
failed = failed || (foo = getfoo()) == null;
failed = failed || (bar = getbar(foo)) == null;
failed = failed || (moo = getmoo(bar)) == null;
failed = failed || (cow = getcow(moo)) == null;
Much clearer - no arrow - and extendable forever.
Please do not go over to the Dark Side and use goto or return.

var foo = getFoo();
var bar = (foo == null) ? null : getBar(foo);
var moo = (bar == null) ? null : getMoo(bar);
var cow = (moo == null) ? null : getCow(moo);
if (cow != null) {
...
}

If you can change the stuff you are calling, you can change it to never ever return null, but a NULL-Object instead.
This would allow you to lose all the ifs completely.

An alternative is to use a "fake" single loop for controlling program flow. I can't say I'd recommend it, but it's definitely better looking and more readable than arrowhead.
Adding a "stage", "phase" or sth like that variable may simplify debugging and/or error handling.
int stage = 0;
do { // for break only, possibly with no indent
var foo = getfoo();
if(foo==null) break;
stage = 1;
var bar = getbar(foo);
if(bar==null) break;
stage = 2;
var moo = getmoo(bar);
if(moo==null) break;
stage = 3;
var cow = getcow(moo);
return 0; // end of non-erroreous program flow
} while (0); // make sure to leave an appropriate comment about the "fake" while
// free resources if necessary
// leave an error message
ERR("error during stage %d", stage);
//return a proper error (based on stage?)
return ERROR;

try
{
if (getcow(getmoo(getbar(getfoo()))) == null)
{
throw new NullPointerException();
}
catch(NullPointerException ex)
{
return; //or whatever you want to do when something is null
}
//... rest of the method
This keeps the main logic of the method uncluttered, and has just one exceptional return. Its disadvantages are that it can be slow if the get* methods are slow, and that it is difficult to tell in a debugger which method returned the null value.

Rex Kerr's answer is indeed very nice.
If you can change the code though,Jens Schauder's answer is probably better (Null Object pattern)
If you can make the example more specific you can probably get even more answers
For example ,depending on the "location" of the methods you can have something like:
namespace ConsoleApplication8
{
using MyLibrary;
using static MyLibrary.MyHelpers;
class Foo { }
class Bar { }
class Moo { }
class Cow { }
internal class Program
{
private static void Main(string[] args)
{
var cow = getfoo()?.getbar()?.getmoo()?.getcow();
}
}
}
namespace MyLibrary
{
using ConsoleApplication8;
static class MyExtensions
{
public static Cow getcow(this Moo moo) => null;
public static Moo getmoo(this Bar bar) => null;
public static Bar getbar(this Foo foo) => null;
}
static class MyHelpers
{
public static Foo getfoo() => null;
}
}

Strange, nobody mentioned method chaining.
If you create once a method chaining class
Public Class Chainer(Of R)
Public ReadOnly Result As R
Private Sub New(Result As R)
Me.Result = Result
End Sub
Public Shared Function Create() As Chainer(Of R)
Return New Chainer(Of R)(Nothing)
End Function
Public Function Chain(Of S)(Method As Func(Of S)) As Chainer(Of S)
Return New Chainer(Of S)(Method())
End Function
Public Function Chain(Of S)(Method As Func(Of R, S)) As Chainer(Of S)
Return New Chainer(Of S)(If(Result Is Nothing, Nothing, Method(Result)))
End Function
End Class
You can use it everywhere to compose any number of functions into an execution sequence to produce a Result or a Nothing (Null)
Dim Cow = Chainer(Of Object).Create.
Chain(Function() GetFoo()).
Chain(Function(Foo) GetBar(Foo)).
Chain(Function(Bar) GetMoo(Bar)).
Chain(Function(Moo) GetCow(Moo)).
Result

This is the one case where I'd use goto.
Your example might not be quite enough to push me over the edge, and multiple returns are better if your method is simple enough. But this pattern can get rather extensive, and you often need some cleanup code at the end. While using most of the other answers here if I can, often the only legible solution is to use goto's.
(When you do, be sure to put all references to the label inside one block so anyone looking at the code knows both the goto's and the the variables are confined to that part of the code.)
In Javascript and Java you can do this:
bigIf: {
if (!something) break bigIf;
if (!somethingelse) break bigIf;
if (!otherthing) break bigIf;
// Conditionally do something...
}
// Always do something else...
return;
Javascript and Java have no goto's, which leads me to believe other people have noticed that in this situation you do need them.
An exception would work for me too, except for the try/catch mess you force on the calling code. Also, C# puts in a stack trace on the throw, which will slow your code way down, particularly if it usually kicks out on the first check.

Related

C# "??" operator - what's wrong?

// EWS Microsoft.Exchange.WebServices.Data.Folder
private Folder _historyFolder;
_historyFolder = GetHistroyFolder(exchangeService) ?? CreateHistortFolder(exchangeService);
public Folder GetHistroyFolder(ExchangeService service)
{
//if found the folder I want - return it , otherwise returns null
}
public Folder CreateHistortFolder(ExchangeService service)
{
var folder = new Folder(service);
folder.DisplayName = _historyFolderName; // "who cares" :)
folder.FolderClass = _historyFolderClass; // "IPF.Note"
folder.Save(WellKnownFolderName.MsgFolderRoot);
return folder;
}
For some reason _historyFolder is always null, although GetHistroyFolder(exchangeService) does return a folder. Why is that?
UPDATE I
I have updated proof for the unbelievers !
If I separate it to 2 lines (without ??) it's OK! but I still wanna understand why the first approach doesn't work...
why down vote? mean ppl..
UPDATE II
Thanks for the all warm people who down vote the question / vote for "close" this thread.
And Thanks for the true warm people who are trying ...
I used the workaround approach, split it to 2 lines
_historyFolder = GetHistroyFolder(exchangeService);
if (_historyFolder == null) _historyFolder = CreateHistortFolder(exchangeService);
you know what funny? Resharper suggests me to return it to how it was before...
Yea , this is a workaround and not real answer for WHY and WTF ... ( .net 4.5 )
UPDATE III
if GetHistroyFolder(..) is return null ( when foreach doesn't find ... ) , CreateHistoryFolder does return Folder object , and _historyFolder is getting the value
Instead of a field why dont you use a property with a backing field. This doesn't exactly solve the problem but at least this makes it easier to debug.
Folder historyFolder
{
get{
if(_historyFolder != null)
return _historyFolder;
_historyFolder = GetHistroyFolder(exchangeService);
if(_historyFolder == null)
_historyFolder = CreateHistortFolder(exchangeService)
if(_historyFolder == null)
throw new NullReferenceException("history folder still null");
return _historyFolder;
}
}
There's no reason for _historyFolder to be NULL, if GetHistroyFolder() is returning an object e.g.
namespace ConsoleApplication1
{
class Program
{
// EWS Microsoft.Exchange.WebServices.Data.Folder
private static object _historyFolder;
static void Main(string[] args)
{
_historyFolder = GetHistroyFolder(null) ?? CreateHistortFolder(null);
Console.WriteLine(_historyFolder == null);
}
public static object GetHistroyFolder(object service)
{
return new object();
//if found the folder I want - return it , otherwise returns null
}
public static object CreateHistortFolder(object service)
{
return null;
}
}
}
I can only imagine that _historyFolder is being set to NULL after GetHistroyFolder() has been called. Your code looks incomplete, are you running in an ASP.NET or something?
EDIT:
In your code, where you call FindFolders(new FolderView()) do this:
FindFolders(new FolderView()).ToList()
Because FindFolders returns an IEnumerable, I think you should call ToList() to ensure that all the folders are returned in one go, not just yielded.
may be "CreateHistoryFolder" return null

How to know whether given is variable of specific class?

I want to know whether passed object is actually reference of variable of specific class or not.
Consider below structure of some class 'ClassA':
public classA
{
string variable1;
int variable2;
method1(ref variable1);
}
Now if in class that contains implementation of method1(Obj object1), I want to check that 'object1' is which variable of specific 'ClassA' ?
Because I want to check in if condition like if object1 is variable1 of ClassA then //to proceed with logic....
Please provide a small example for the same.
The closest you could get to this in safe code is using expressions, but honestly you probably don't want to do this. It'd be a nightmare to try and debug, and there's probably another way to go about it. For example, is there any reason variable1 can't be of a specific type?
Now that I've spoken reason, the approach using expressions goes something like this (This is from a debugging helper, I would never use this approach in anything remotely serious. Note: A lot of exception handling and other code is stripped from this, also note how ugly and hackish it looks, that's all why you really shouldn't do this):
public static void DoStuffWithParameter<T>(Expression<Func<T>> paramExpression)
{
if (paramExpression == null) throw new ArgumentNullException("paramExpression");
var body = ((MemberExpression)paramExpression.Body);
var paramName = body.Member.Name;
var param = ((FieldInfo)body.Member)
.GetValue(((ConstantExpression)body.Expression).Value);
var declaringType = param.DeclaringType;
var paramValue = paramExpression
.Compile()
.Invoke();
if(declaringType.Equals(typeof(ClassA)))
{
//do stuff
}
}
To use that you'd use something like:
DoStuffWithParameter(()=>myClass.VarA);
I found solution. The simplest way to do this is to pass object of sender in method1 and proceed, like below.
method1(Object sender, ref Object var)
{
if(sender is classA)
{
classA senderObj= (classA) sender;
if((string)var == senderObj.variable1)
{
// Logic for variable1
}
else if((int)var == senderObj.variable2)
{
// Logic for variable2
}
. . .
}
}

How to make Code Contracts believe that variable is not null?

I have some factory method
public T Create<T> () where T : class
{
Contract.Ensures(Contract.Result<T>() != null);
T result = this.unityContainer.Resolve<T>();
return result;
}
The I try to build the project i get the warning:
CodeContracts: ensures unproven: Contract.Result() != null
I understand that IUnityContainer interface does not have any contracts so Code Contracts think that varible may be null and there is no way to prove that Create() will return not null result.
How in this case I can make Code Contracts belive that result variable is not null?
I first tried to call Contract.Assert
public T Create<T> () where T : class
{
Contract.Ensures(Contract.Result<T>() != null);
T result = this.unityContainer.Resolve<T>();
Contract.Assert(result != null);
return result;
}
But it takes me another warning:
CodeContracts: assert unproven
I tried make check for null and this makes all warnings gone:
public T Create<T> () where T : class
{
Contract.Ensures(Contract.Result<T>() != null);
T result = this.unityContainer.Resolve<T>();
if (result == null)
{
throw new InvalidOperationException();
}
return result;
}
But i'm not sure this is good solution to throw exception manually. May be there is some way to solve problem using Code Contracts only?
Thank you.
I think you want Contract.Assume:
Contract.Assume(result != null);
From the docs:
Instructs code analysis tools to assume that the specified condition is true, even if it cannot be statically proven to always be true.
This will still validate the result at execution time if you have the rewriter appropriately configured.
Like if((result ?? 0) == 0){}
To make this more clear (readable) you can define an extension method.
Edit
#allentracks answer is more precise for your question

Checking if an object is null in C#

I would like to prevent further processing on an object if it is null.
In the following code I check if the object is null by either:
if (!data.Equals(null))
and
if (data != null)
However, I receive a NullReferenceException at dataList.Add(data). If the object was null, it should never have even entered the if-statement!
Thus, I'm asking if this is proper way of checking if an object is null:
public List<Object> dataList;
public bool AddData(ref Object data)
bool success = false;
try
{
// I've also used "if (data != null)" which hasn't worked either
if (!data.Equals(null))
{
//NullReferenceException occurs here ...
dataList.Add(data);
success = doOtherStuff(data);
}
}
catch (Exception e)
{
throw new Exception(e.ToString());
}
return success;
}
If this is the proper way of checking if the object is null, what am I doing wrong (how can I prevent further processing on the object to avoid the NullReferenceException)?
It's not data that is null, but dataList.
You need to create one with
public List<Object> dataList = new List<Object>();
Even better: since it's a field, make it private. And if there's nothing preventing you, make it also readonly. Just good practice.
Aside
The correct way to check for nullity is if(data != null). This kind of check is ubiquitous for reference types; even Nullable<T> overrides the equality operator to be a more convenient way of expressing nullable.HasValue when checking for nullity.
If you do if(!data.Equals(null)) then you will get a NullReferenceException if data == null. Which is kind of comical since avoiding this exception was the goal in the first place.
You are also doing this:
catch (Exception e)
{
throw new Exception(e.ToString());
}
This is definitely not good. I can imagine that you put it there just so you can break into the debugger while still inside the method, in which case ignore this paragraph. Otherwise, don't catch exceptions for nothing. And if you do, rethrow them using just throw;.
in C# > 7 use if (obj is null)
For not null use:
   C# 7-8:  if (obj is object)
   C# 9-:    if (obj is not null)
These will ignore any == or != defined by the object (unless of course you want to use them for null checks)
For more, in the C# Language Reference, see is operator.
C# 6 has monadic null checking :)
before:
if (points != null) {
var next = points.FirstOrDefault();
if (next != null && next.X != null) return next.X;
}
return -1;
after:
var bestValue = points?.FirstOrDefault()?.X ?? -1;
Your dataList is null as it has not been instantiated, judging by the code you have posted.
Try:
public List<Object> dataList = new List<Object>();
public bool AddData(ref Object data)
bool success = false;
try
{
if (!data.Equals(null)) // I've also used if(data != null) which hasn't worked either
{
dataList.Add(data); //NullReferenceException occurs here
success = doOtherStuff(data);
}
}
catch (Exception e)
{
throw;
}
return success;
}
[Edited to reflect hint by #kelton52]
Simplest way is to do object.ReferenceEquals(null, data)
Since (null==data) is NOT guaranteed to work:
class Nully
{
public static bool operator ==(Nully n, object o)
{
Console.WriteLine("Comparing '" + n + "' with '" + o + "'");
return true;
}
public static bool operator !=(Nully n, object o) { return !(n==o); }
}
void Main()
{
var data = new Nully();
Console.WriteLine(null == data);
Console.WriteLine(object.ReferenceEquals(null, data));
}
Produces:
Comparing '' with 'Nully'
True
False
As of C# 9 you can do
if (obj is null) { ... }
For not null use
if (obj is not null) { ... }
If you need to override this behaviour use == and != accordingly.
No, you should be using !=. If data is actually null then your program will just crash with a NullReferenceException as a result of attempting to call the Equals method on null. Also realize that, if you specifically want to check for reference equality, you should use the Object.ReferenceEquals method as you never know how Equals has been implemented.
Your program is crashing because dataList is null as you never initialize it.
The problem in this case is not that data is null. It is that dataList itself is null.
In the place where you declare dataList you should create a new List object and assign it to the variable.
List<object> dataList = new List<object>();
With c#9 (2020) you can now check a parameter is null with this code:
if (name is null) { }
if (name is not null) { }
You can have more information here
As of C# 8 you can use the 'empty' property pattern (with pattern matching) to ensure an object is not null:
if (obj is { })
{
// 'obj' is not null here
}
This approach means "if the object references an instance of something" (i.e. it's not null).
You can think of this as the opposite of: if (obj is null).... which will return true when the object does not reference an instance of something.
For more info on patterns in C# 8.0 read here.
In addition to #Jose Ortega answer,
its better for use extension method
public static bool IsNull(this object T)
{
return T == null;
}
And use IsNull method for all of object like:
object foo = new object(); //or any object from any class
if (foo.IsNull())
{
// blah blah //
}
Jeffrey L Whitledge is right. Your `dataList´-Object itself is null.
There is also another problem with your code: You are using the ref-keyword, which means the argument data cannot be null! The MSDN says:
An argument passed to a ref parameter must first be initialized. This differs from out, whose arguments do not have to be explicitly initialized before they are passed
It's also not a good idea to use generics with the type `Object´. Generics should avoid boxing/unboxing and also ensure type safety. If you want a common type make your method generic. Finally your code should look like this:
public class Foo<T> where T : MyTypeOrInterface {
public List<T> dataList = new List<T>();
public bool AddData(ref T data) {
bool success = false;
try {
dataList.Add(data);
success = doOtherStuff(data);
} catch (Exception e) {
throw new Exception(e.ToString());
}
return success;
}
private bool doOtherStuff(T data) {
//...
}
}
As others have already pointed out, it's not data but rather likely dataList that is null. In addition to that...
catch-throw is an antipattern that almost always makes me want to throw up every time that I see it. Imagine that something goes wrong deep in something that doOtherStuff() calls. All you get back is an Exception object, thrown at the throw in AddData(). No stack trace, no call information, no state, nothing at all to indicate the real source of the problem, unless you go in and switch your debugger to break on exception thrown rather than exception unhandled. If you are catching an exception and just re-throwing it in any way, particularly if the code in the try block is in any way nontrivial, do yourself (and your colleagues, present and future) a favor and throw out the entire try-catch block. Granted, throw; is better than the alternatives, but you are still giving yourself (or whoever else is trying to fix a bug in the code) completely unnecessary headaches. This is not to say that try-catch-throw is necessarily evil per se, as long as you do something relevant with the exception object that was thrown inside the catch block.
Then there's the potential problems of catching Exception in the first place, but that's another matter, particularly since in this particular case you throw an exception.
Another thing that strikes me as more than a little dangerous is that data could potentially change value during the execution of the function, since you are passing by reference. So the null check might pass but before the code gets to doing anything with the value, it's changed - perhaps to null. I'm not positive if this is a concern or not (it might not be), but it seems worth watching out for.
public static bool isnull(object T)
{
return T == null ? true : false;
}
use:
isnull(object.check.it)
Conditional use:
isnull(object.check.it) ? DoWhenItsTrue : DoWhenItsFalse;
Update (another way) updated 08/31/2017 and 01/25/2021. Thanks for the comment.
public static bool IsNull(object T)
{
return (bool)T ? true : false;
}
Demostration
And for the records, you have my code on Github, go check it out:
https://github.com/j0rt3g4/ValidateNull
PS: This one is especially for you Chayim Friedman, don't use beta software assuming that is all true. Wait for final versions or use your own environment to test, before assuming true beta software without any sort of documentation or demonstration from your end.
Whenever you are creating objects of class you have to check the whether the object is null or not using the below code.
Example:
object1 is object of class
void myFunction(object1)
{
if(object1!=null)
{
object1.value1 //If we miss the null check then here we get the Null Reference exception
}
}
There is a one-liner in .NET 6
ExampleMethod(null);
void ExampleMethod(object param)
{
ArgumentNullException.ThrowIfNull(param);
// Do something
}
I just followed a method that we would usually follow in java script. To convert object to string and then check whether they are null.
var obj = new Object();
var objStr = obj.ToString();
if (!string.IsNullOrEmpty(objStr)){
// code as per your needs
}
I did more simple (positive way) and it seems to work well.
Since any kind of "object" is at least an object
if (MyObj is Object)
{
//Do something .... for example:
if (MyObj is Button)
MyObj.Enabled = true;
}
You can try like below
public List<Object> dataList;
public bool AddData(ref Object data)
bool success = false;
try
{
if (data != null)
{
dataList.Add(data);
success = doOtherStuff(data);
}
}
catch (Exception e)
{
throw new Exception(e.ToString());
}
return success;
}
Here are some extensions I use:
/// <summary>
/// Extensions to the object class
/// </summary>
public static class ObjectExtensions
{
/// <summary>
/// True if the object is null, else false
/// </summary>
public static bool IsNull(this object input) => input is null;
/// <summary>
/// False if the object is null, else true
/// </summary>
public static bool NotNull(this object input) => !IsNull(input);
}
public bool IsVisible(object ClaimCount)
{
bool flag = true;
#region || HIDE COLUMNS ON CONDITION BASIS
if (!String.IsNullOrEmpty(Convert.ToString(ClaimCount)))
{
Int32 ClaimCnt = Convert.ToInt32(ClaimCount);
if (ClaimCnt == 1)
{
flag = false;
}
}
#endregion
return flag;
}

Multiple methods that need to be handled the same way

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:
it doesn't needs to be transactional.
strFailure does not hide exceptions it wraps them
completely when necessary
Thanks.
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.
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.
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);
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 );
}
}

Categories