Cleaner code: Re-factor multiple nested if statements - c#

I have code that looks something like this:
if(condition1)
{
//do some stuff
if(condition2)
{
//do some other stuff
if(condition3)
{
//do some more stuff
if(condition4)
{
//you probably got the point by now...
}
}
}
And I would like to re-factor it to code that looks better and is easier to follow.
So far the best I got Is:
do{
if(!condition1){break;}
//do some stuff
if(!condition2){break;}
//do some other stuff
if(!condition3){break;}
//do some more stuff
if(!condition4){break;}
//you probably got the point by now...
}while(false);
My question is:
Is there another better way I am missing?
I don't think it is relevant, but I am using C#...

Possibly encapsulate the functionality you need for each boolean condition into a method and use the method instead of specifying condition1, condition2, condition3 etc.
private boolean isRed() {
//do some stuff
}
private boolean isBlue() {
//do some other stuff
}
private boolean isGreen() {
//do some more stuff
}
...
if(isRed() && isBlue() && isGreen()) {
//do some more stuff
}

Since you are using C#, the idea of #dseibert could be extended a little bit more and made flexible using delegates, in this case Func.
You could create a List that holds Func's and add as many functions with the signature bool function(void) as you want and then evaluate the result of all of them using LINQ.
Three example functions to play with:
private bool isRed()
{
System.Console.WriteLine("red");
return true;
}
private bool isBlue()
{
System.Console.WriteLine("blue");
return false;
}
private bool isGreen()
{
System.Console.WriteLine("green");
return true;
}
List holding Funcs, that is filled with the test functions and initialized result:
var actions = new List<Func<bool>>();
actions.Add(() => isRed());
actions.Add(() => isGreen());
actions.Add(() => isBlue());
var result = true; // initial value
Evaluate all functions at once:
actions.ForEach(a => result &= a());
System.Console.WriteLine(result);
Now the only thing that you need to do is create a new method and add it to the list.
The downside of this solutions is that every method is always called even if the result is already false, but the code within the ForEach extension method could be optimized.

Related

Instantiating an object and setting a variable inside an array at the same time

I want to instantiate an object and change/set a variable inside an array with a short (for efficiency purposes) amount of code, but this doesn't work:
private ClickBox[] clickBoxes = new ClickBox[]
{
new ClickBox().OnClick += (#object) =>
{
}
};
class ClickBox
{
public delegate void ClickEvent(Object #object);
private ClickEvent clickEvent;
public ClickEvent OnClick
{
get { return clickEvent; }
set { clickEvent = value; }
}
}
Does anyone know a way to return the object instead of the variable in this code? I know it would work to set the ClickEvent after the array is made, but this would be very inefficient for a large number of items.
Thank you.
You should really write a builder method to implement this.
Something really simple could look like this:
static ClickBox createClickBox(Action<ClickBox> subscribe)
{
var result = new ClickBox();
subscribe(result);
return result;
}
You could use that to initialise an array that is a field of the class like so:
readonly ClickBox[] clickBoxes =
{
createClickBox(cb => cb.OnClick += o => { /* Code 1 */ }),
createClickBox(cb => cb.OnClick += o => { /* Code 2 */ })
};
But I must agree with others who say this is a bit of a code smell - although without more context about how you really intend to use this, it's hard to say for sure.
Also, when talking about efficiency: I assume you are talking in terms of reducing the number of lines of code, rather than performance.

InvokeRequired to checkbox

I just need to create a function to checkbox that will return the current value of checkbox.
I wrote :
private void Checkbox_check()
{
if (checkBox1.InvokeRequired)
return (int)checkBox1.Invoke(new Func<int>(checked));
else
return checkBox1.Checked; // bad here i know
}
What is bad here, can someone just write correctly this function? I need Invoke because can't use in another Thread without invoke. I just search a forum and web about help but can't find solution anywhere.
Don't use Func<> as it doesn't return anything. Use Action instead.
private void Checkbox_check()
{
if (checkBox1.InvokeRequired)
checkBox1.Invoke(new Action(Checkbox_check));
else
{
// do what you like to do on the ui context
// checkBox1.Checked; // bad here i know, yep...
}
}
Getting the checked state from another thread, you could do like this:
private bool Checkbox_check()
{
// result value.
bool result = false;
// define a function which assigns the checkbox checked state to the result
var checkCheckBox = new Action(() => result = checkBox1.Checked);
// check if it should be invoked.
if (checkBox1.InvokeRequired)
checkBox1.Invoke(checkCheckBox);
else
checkCheckBox();
// return the result.
return result;
}
I would not advise this, this could lead to deadlocks etc. I advise you to pass the checked value on the threadstart, so you don't have to do any crossthread calls.
You should write it this way:
private void Checkbox_check()
{
if (checkBox1.Invoke:DRequired)
return (int)checkBox1.Invoke(new Func<int>(checked));
else
return checkBox1.Checked.(initInvoke);
}

How to add to a chain of methods by checking if statements

I don't know the right terminology for this but i have a simple C# code snippet which tweens some objects like this:
camera.gameObject.transform.DOMove(target,3.0f)
.SetEase(Ease.InOutQuad)
.OnComplete(animation.FadeIn);
But what i need to do is add another method to this chain based on a certain condition like this:
camera.gameObject.transform.DOMove(target,3.0f)
.SetEase(Ease.InOutQuad)
//the general idea
if(visible == true){
.OnStart(animation.FadeOut);
}
.OnComplete(animation.FadeIn);
Obviously this is a syntax error, but i do not know the correct way to handle something like this for the syntax.
How should i approach it?
You would need to place the entire chunk in your if-else statement, you cannot break it down:
if(visible == true){
camera.gameObject.transform.DOMove(target,3.0f)
.SetEase(Ease.InOutQuad) .OnStart(animation.FadeOut).OnComplete(animation.FadeIn);
}
else {
camera.gameObject.transform.DOMove(target,3.0f)
.SetEase(Ease.InOutQuad).OnComplete(animation.FadeIn);
}
Alertnatively:
var intermediateObject = camera.gameObject.transform.DOMove(target,3.0f)
.SetEase(Ease.InOutQuad);
if (visible) {
intermediateObject.OnStart(animation.FadeOut).OnComplete(animation.FadeIn);;
}
else {
intermediateObject.OnComplete(animation.FadeIn);;
}
The var keyword means that you do not need to worry about the type of the object yourself, but then again, its usage does hinder readability (in my opinion).
If you want to keep everything in one chain you can try using If extension:
internal static T If<T> (this T source, bool isTrue, Action<T> thenAction) {
if (isTrue) {
thenAction(source);
}
return source;
}
This extension will work if OnStart returns same camera object. Otherwise, If extension should be changed.
Then your code would look like this:
camera.gameObject.transform.DOMove(target,3.0f).
SetEase(Ease.InOutQuad)
If(visible == true, value => value.OnStart(animation.FadeOut)).
OnComplete(animation.FadeIn)
If OnStart actually returns different object:
internal static T If<T> (this T source, bool isTrue, Func<T, T> thenFunction) =>
isTrue ? thenFunction(source) : source;

Which of the following code blocks are more logical?

Imagine a condintion should be true for a method to do its stuff. Which block represents the best approach (performance related and readability), or if not what is your suggestion?!
private void method()
{
if(!condition)
{
MessageBox.Show("ERROR!");
return;
}
else
{
//DO STUFF
}
}
OR
private void method()
{
if(condition)
{
//DO STUFF
}
else
{
MessageBox.Show("ERROR!");
return;
}
}
Neither. Use a guard clause instead:
private void method()
{
if(!condition)
{
MessageBox.Show("ERROR!");
return;
}
//inputs have been checked, proceed with normal execution
}
Done this way you can deal with all the exceptional behaviour up-front and avoiding excessive levels of indentation for the normal execution path.
Well, neither, as you wouldn't use both else and return.
So, you would either do:
private void method() {
if (!condition) {
MessageBox.Show("ERROR!");
} else {
//DO STUFF
}
}
or:
private void method() {
if (condition) {
//DO STUFF
} else {
MessageBox.Show("ERROR!");
}
}
or:
private void method() {
if (!condition) {
MessageBox.Show("ERROR!");
return
}
//DO STUFF
}
or:
private void method() {
if (condition) {
//DO STUFF
return;
}
MessageBox.Show("ERROR!");
}
Which you use depends mostly on what the code actually does. The code is seldom as simple as in the examples, so it matters what more the code will do.
The first two have the advantage of having a single exit point, which often makes it easier to follow the code. You would usually put the shorter code first, as it's easier to spot there than in an else after a larger code block.
The third is often used to validate input before continuing with the main code, and you can easily have more than one validation:
private void method() {
if (!condition) {
MessageBox.Show("ERROR!");
return
}
if (!anotherCondition) {
MessageBox.Show("ANOTHER ERROR!");
return
}
//DO STUFF
}
The fourth is useful if you have several conditions that you don't want to put in the same if statement:
private void method() {
if (condition) {
var data = GetSomeData();
if (data.IsValid) {
var moreData = GetSomeMoreData();
if (moreData.IsValid) {
//DO STUFF
return;
}
}
}
MessageBox.Show("ERROR!");
}
Second! Second!
But I do admit to doing the first sometimes if the "//DO STUFF" is really long and nested.
I prefer an "If condition" approach as opposed to the negation of a condition, but that's just personal preference.
It depends.
In most cases, the second version.
if the amount of code in the (!condition) block is only a few lines of code, and the code in the (condition) block is a LOT of code, then I'd reverse the answer. it's easier to read through the if statement if you can see the "else" without having to scroll.
I prefer a guard clause as David mentions, but in the general case you should put the most common case first. It makes it easier to follow the flow of a method.
Readability/standards wise. I would accept number 2. I don't think there is a difference performance wise, but I'm not a low-level guy.
As usually this is a question which asks for the following answer: "it depends" and I'll show by two examples.
IF NOT CONDITION
For the ASP .Net Web Forms validation I'm seeing very often this code
protected void btSubmit_OnClick(object sender, EventArgs e)
{
Page.Valide();
if (!Page.IsValid)
return;
var customer = new Customer();
// init 20 properties of customer
....
var bo = new CustomerBO();
bo.Save(customer);
}
There is another one much more popular:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
}
}
IF CONDITION
public void UpdateCustomer(int customerId, string ...../*it might be a customer type also*/)
{
using (var ctx= CreateContext())
{
var customer = ctx.Customers.FirstOrDefault(c=>c.CustomerId = customerId);
if ( customer != null)
{
/*code update 20 properties */
}
}
}
I hope the code is clear :P
This is more of a style question than a "logical" question. Both of these approaches work, and which one you will use generally depends on your style as a thinker/developer.
That said, once you start using either one of these styles, it generally pays to be consistent. Having large classes where some functions do it the first way and others the second way can lead to maintainability concerns later.
Robert Martin's Clean Code presents an interesting chapter on functions that suggests, whichever way you choose, the //DO STUFF part should be another function call
Functions Should Only Do One Thing

Background worker run worker completed

depending on the do work method my result could either be a List of Strings or a list of byte[]
How can we check the RunWorkerCompletedEventArgs e -
if (e is List<String>)
is this the correct way to check?
No, this is not the right way.
The correct way is to use this:
if(e.Result is List<string>)
{
//...
}
else if(e.Result is List<byte[]>)
{
//...
}
else
{
//...
}
e will always be of type RunWorkerCompletedEventArgs. But this class contains a property Result that contains the result of your DoWork event handler. That's the one, you need to check.
Yes, that's one possible way to do it.
If you only have two types it would be quite easy:
if(e.Result is List<string>)
{
}
else if(e.Result is List<byte[]>)
{
}
else
{
}
But the problem comes in to play if you have to support more than just two or three. In that case i'm going to create a Dictionary<Type, Action<object>> and write individual functions for each type. Something like this:
var supportedTypes = new Dictionary<Type, Action<object>>();
supportedTypes.Add(typeof(List<string>), ComputeListOfStrings);
supportedTypes.Add(typeof(List<byte[]>), ComputeListOfByteArrays);
private void ComputeListOfString(object listOfStrings)
{
var list = (List<string>)listOfStrings;
}
private void ComputeListOfByteArrays(object listOfByteArrays)
{
var list = (List<byte[]>)listOfByteArrays;
}
This makes it more simple to support new types and also stays to be O(1) while the if-else-if runs into the order-matters problem.
Used will this in your background worker as followed:
worker.OnRunWorkerCompleted += (sender, e) =>
{
Action<object> supportedAction;
supportedTypes.TryGetValue(e.Result.GetType(), out supportedAction);
if(supportedAction != null)
{
supportedAction();
}
};
the e.Result is the property with your results, so to get the type you can do:
if(e.Result.GetType().Equals(typeof(List<String>)))

Categories