I see now after writing it down that this answer is to some extent a mixture of that of Matthew Watson and that of Victor, but I will provide it anyway.
First of all, I agree with Victor that getting rid of all the nesting is an important improvement. I also agree with them that splitting your code into methods can be very helpful in that regard.
Secondly, I agree with Matthew that if the result of do A
can be used directly to define the result of condition3
, it may also be used directly rather than calling it before evaluating condition3
.
If condition3
can be extracted to a method that takes the result of do A
as an input parameter, you could avoid nesting entirely by creating one method per nesting level. As an example:
public static void Main()
{
DoYourThing();
do E;
}
DoYourThing()
{
if (<condition1>)
{
DoYourNextThing();
}
else
{
do D;
}
}
DoYourNextThing()
{
if (<condition2> && Condition3(A()))
{
do B;
}
else
{
do C;
}
}
private bool Condition3(object a)
{
//...
}
If condition3
cannot be extracted to a method that takes the result of do A
as an input parameter, DoYourNextThing()
may need to be implemented differently. One possibility is:
DoYourNextThing()
{
if (ShouldDoB())
{
do B;
}
else
{
do C;
}
}
ShouldDoB()
{
if (!condition2)
{
return false;
}
var a = do A;
return condition3; // based on a
}
As a side note, I'd say that using descriptive variable names and method names is generally more important than refactoring away nested loops; whereas doing both (in a way that enhances comprehension and readability) is gold.
That being said, I trust that OP is using generic names simply to present a clear and easy example of the logic they are trying to achieve.