I usually fall into a situation where goto seems to be the best option to my mind. But I have read several times not to use it, and there is always an alternative. Now, I am trying something like this:-
try{
//Something that requires internet connectivity;
}
catch{
//Show a message-Internet connectivity lost,and go back to try
//-->FYI--Ignore "show message", because I am just appending this text to a
// textbox. So there won't be a problem of multiple ShowMessage Boxes.
}
Now, the best option seems to me is to use goto in catch statement, but I am trying to avoid it. try is the first statement in a function, and if I recall that function, I am piling up stacks, so thats not a better option as well. What alternative can I take?
Use a while loop with a flag
var tryAgain = true;
while (tryAgain)
{
try
{
...
tryAgain = false;
}
catch (...)
{
tryAgain = ...
}
}
In this particular case there is nothing wrong with calling the same function recursively and keeping a counter with the number of times you've called it. Something like this (in pseudo code):
public void DoMyInternetThing(int numberOfAttemptsRemaining)
{
try
{
//do stuff
}
catch (ConnectionException)
{
if (numberOfAttemptsRemaining <= 0)
throw new SomethingBadHappenedException();
DoMyInternetThing(numberOfAttemptsRemaining - 1);
}
}
As with anything recursive you need to ensure you structure it correctly, but this works nicely (I've used it myself) and it avoids your goto (which is not bad in itself, but use of it can lead to spaghetti or badly structured code).
If you want to try again, wrap your try-catch in a do-while loop.
Related
Is it possible to exit a scope in C# like it's possible to break out of a loop for example?
private void a()
{
// do stuff here
{
// do more stuff here
break;? //<-- jump out of this scope here!! break won't work
// this further code should not be executed
}
// do stuff here
}
You can use break to break out of a loop or switch, but you cannot break out of a simple block like this.
There are ways to achieve this, for example using goto or artificial while loop, but it definitely sounds like a code smell.
You can achieve what you want using simple condition which will make your intention much more clear.
Instead of:
DoSomething();
if (a == 1) // conditional break
{
break;
}
DoSomethingElse();
break; // unconditional break (why though)
UnreachableCode(); // will generate compiler warning, by the way
You can do:
DoSomething();
if (a != 1) // simple condition
{
DoSomethingElse();
if (false) // why though
{
UnreachableCode(); // will generate compiler warning, by the way
}
}
Alternatively, you can extract this part to a separate named method and short-circuit using return statements. Sometimes, it really makes code more readable, especially when you have a return value:
private void a()
{
// do stuff here
MeaningfulNameToDescribeWhatYouDo();
// do stuff here
}
private void MeaningfulNameToDescribeWhatYouDo()
{
// do more stuff here
if (condition)
{
return; //<-- jump out of this scope here!!
}
// this further code should not be executed
}
Yes, it is possible to use goto statements but I strongly suggest you don't use them until you gain more experience with the language. I never use goto and I don't know of any programmers who do, because it can make your code a giant spaghetti mess and there are generally better alternatives.
There's ways to use them responsibly, but from your question it sounds like you're not sure how to properly use if/else/while etc. statements. Instead it's better to use proper flow controls.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto
I have a program that is completely functional, and I am now refactoring it. I am just in the process of learning c# so the original code was pretty terrible despite the fact that it ran just fine. One of the requirements of the program is that the user be able to return to the main menu at any point. I accomplished this as follows:
static bool bouncer = false
static void Exit(string input)
{
if (input == "\t")
{
bouncer = true
}
}
static string Prompt(string msg)
{
// takes input and passes it to Exit() then returns the input
}
static string FunctionA()
{
while(true)
{
if (bouncer == true)
{
break;
}
Prompt("whatever")
if (bouncer == true)
{
break;
}
Prompt("whatever")
if (bouncer == true)
{
break;
}
// return some stuff
}
}
static void Main()
{
bouncer = false
// writes the menu to console and handles UI
// FunctionA
{
The variable bouncer gets set to true if the user enters the "tab" character at any input point. The proliferation of break statement conditionals provides the structure that actually breaks out back to Main(). This is obviously not a very good solution and it makes the code hard to read.
Other attempts that I considered to accomplish the same task are:
Goto statement that jumps straight back to Main(). I scrapped this because goto has a very limited scope in c# and I don't think there is any good way to make it workable in this situation.
Calling Main() directly from Exit(). This is probably a bad idea, and I can't do it anyway because apparently Main() is "protected" in some way.
Using an event to react to TAB or ESC being pressed. It's unclear to me how I could use an event to do this since I still wouldn't be able to break right out of the event. My understanding is that the break statement has to actually be contained in the loop that needs to be broken as opposed to being written into a different function that is called from within the loop.
Any suggestions are greatly appreciated. I'm hoping there's something to be done with event handling or that I've overlooked something more simple. Thanks!
As a matter of coding style, the way it is works, but is seen as ugly. Unfortunately, if you need to break out immediately between sections of work, there is not a lot of ways around that.
You can change your current format of using breaks to using "if( bContinue ) { /* do next section of work */ }" control style. It changes the code from break out of the while loop to this:
static string FunctionA()
{
bool bContinue = true;
while( true == bContinue )
{
// Do initital work.
//
// Initial work can set bContinue to false if any error condition
// occurs.
if( true == bContinue )
{
// Do more work.
int returnCheck = MakeACall(); // Presume MakeACall returns negative interger values for error, 0 or positive values for success or success with condition/extra information.
if( 0 < returnCheck )
{
bContinue = false;
}
}
if( true == bContinue )
{
Prompt("whatever")
// Do more work.
bContinue = MakeASecondCall(); // Presume that MakeASecondCall returns true for success, false for error/failure
}
if( true == bContinue )
{
Prompt("whatever")
// Do more work.
// If error encountered, set bContinue to false.
}
if( true == bContinue )
{
Prompt("whatever else")
// Do more work.
// If error encountered, set bContinue to false.
}
// Done with loop, so drop out.
bContinue = false;
// return some stuff
}
}
Looking at your pseudo code, it reads like you only do a single pass through your work loop. If so, you can switch to a Do-While(false) format, and use the break to just drop to the bottom. Or, if you are only doing a single pass through your FunctionA, just do away with the While or Do-While control structure, and just use the if(true==bContinue){ /* Do more work */ }. It is not the cleanest of code, but when you perform long periods of serial work, you end up with such structures if you are not going to use a while or do-while for controlling the flow.
The disadvantage to using the if(bContinue){} style is that when an error condition occurs during the early stages of the process, the code does not exit out as quickly from the function as a break out of the while() or do-while() structure if the error occurs near the top of the work, as there will be the series of if statements that the code will test and then skip over. But it is readable, and if you use a descriptive name for your control variable (ie, nContinue or bContinue or workLoopControl) it should be fairly obvious that it is the master control flag for the function's work flow to whoever works or reviews the code after you.
Instead of an infinite loop and break statements, try using a conditional flag instead.
static void FunctionA()
{
bool done = false;
string response = string.Empty;
while (!done)
{
response = Prompt("whatever");
if(response == '\t')
{
done = true;
}
}
}
As a side note, I'm not sure why you have 'string' as the return type of several methods (e.g., 'FunctionA') when you aren't using the return value. That's why the code I gave above has it as 'void'.
i have the following 3 examples which does the same thing
//case1 do it if the condition is valid
private void SetMultiplePropertyValues()
{
if (Keyboard.GetKeyStates(Key.CapsLock) == KeyStates.Toggled)
{
//do somthing
}
}
//case 2 return if the condition is not valid
private void SetMultiplePropertyValues()
{
if (Keyboard.GetKeyStates(Key.CapsLock) != KeyStates.Toggled) return;
//do somthing
}
//case 3 checking the condition in the calling scope
if (Keyboard.GetKeyStates(Key.CapsLock)== KeyStates.Toggled)
SetMultiplePropertyValues())
private void SetMultiplePropertyValues()
{
//do somthing
}
which one would you go with and why
They do not do the same thing because in the first two cases the name of the method is a lie; the method name should be SetValuesIfTheKeyStateIsToggled or TryToSetValues or some such thing. Don't say you're going to do a thing and then not do it. More generally: separate your concerns. I would choose a fourth option:
public void TryToFrob()
{
if (CanFrob()) DoFrob();
}
private bool CanFrob()
{
return Keyboard.GetKeyStates(Key.CapsLock) == KeyStates.Toggled;
}
private void DoFrob()
{
// frob!
}
Notice what is public and what is private.
This is a silly looking example because each one is so simple, but one can easily imagine a situation in which these methods are complex. Keep your policies and your mechanisms logically separated. The mechanism is "is the keyboard in a particular state?" The policy is "I have some conditions under which I can frob; we must never frob unless those conditions are met".
First of all, as we can see at code comments, they don't do the same thing. So I think that you're talking about code architecture rather than functionality.
Second, here in SO isn't about giving opinions, but I'll try say to you concrete things about these differences.
1- Common if approach
if (true == false)
{
return true;
}
vs.
2 - Single line if approach
if (true == false) return true;
Most of code convetions says to use the option 1, because they're easier to read and understant code, and avoid some mistakes. We need to also understand that convetions are not rules! so they're just convetions, but really try to avoid option 2 in most of the cases.
One more thing, some code convetions also says that's ok using option 2 when you need something very simple, like this given example which is really easy to read and understand. But take this like an exception from the 'rules'.
I'm not sure if my title is really correct. I've looked around and searched but not found anything so please forgive me if my problem has been answered already.
What I would like to do is call a function but not have to come back to the calling line of code. e.g
public static void temp(obj) {
switch (obj.id) {
case "1" :
if(blah) {
obj.id = "2";
temp(obj);
}
break;
case "2" :
obj.response = "done";
break;
}
}
so basically I dont want to eventually come back to my temp(obj) in the first case and fully pass control. Does this make sense, is it even possible and my architecture is all wrong?
Thank you for your time.
Let me see if I understand the question:
You've got a function Foo(), which calls function Bar(). (I wanted to remove the recursion you had in your example for simplicity, please correct me if that was important.) When function Bar() returns, you want control to pass not back to Foo(), but to Foo's caller?
This is probably possible in lower-level languages, like C, by hacking the stack and not placing Foo()'s return address there, so that when Bar() tried to return, it would jump to Foo's caller instead.
However, in C#, no. The call stack is a stack, and control will pass back in order. The only thing you can do would be to put a return statement after each call to Bar().
Edit:
"recursive calls without them being recursive"
How about this:
bool doItAgain = true;
while(doItAgain)
{
doItAgain = false;
// process, with your switch statement or whatever.
if(...)
{
doItAgain = true;
continue; // if necessary, skip any code after this statement. May not be necessary if you have things set up right.
}
}
If this were C++, you could eliminate the break and let the case "1" fall through, but this is not allowed in C# switch statements.
public static void temp(obj) {
if (obj.id == "1") {
obj.id = "2";
temp(obj);
}
if (obj.id == "2")
obj.response = "done";
}
Do you need the recursive call? This code retains your recursive call and sets obj.response to "done" after changing obj.id to "2". However, obj.response is set twice because of the recursive call. What are you trying to do?
I'm not sure what you exactly intend, but it sounds like a callback to me. Here is one possible example:
void DoSome()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { RunMe(); ReturnTo(); }));
}
void RunMe() { }
void ReturnTo() { }
You start in DoSome() and continue, when RunMe is finished ReturnMe is called.
Look at this:
foreach(Object Item in comboBox1.Items)
{
if (Convert.ToString(Item) == Convert.ToString(dsGirasol.Tables["DatosGirasol"].Rows[contador][0]))
{
repetido = true;
break;
}
else
{
repetido = false;
}
}
Note that both of the possible outputs have a messagebox. However when I run this, nothing appears at all, and the rest of the code continues to run...
EDIT: Added the surrounding loop!
Why do you want the break there for? Try this:
if (Convert.ToString(Item) == Convert.ToString(dsMaiz.Tables["DatosMaiz"].Rows[contador][0]))
{
repetido = true;
MessageBox.Show("Encontre uno igual");
}
else
{
repetido = false;
MessageBox.Show("Encontre uno diferente");
}
Try evaluating the left and right parts of the condition before you evaluate the equality.
I can only imagine that it must be throwing an exception that is silently caught.
This will help you debug the issue.
eg:
var left = Convert.ToString(Item);
var right = Convert.ToString(dsMaiz.Tables["DatosMaiz"].Rows[contador][0]);
if (left == right)
{
...
}
else
{
...
}
EDIT:
Now that I see you are using a loop, go back to basics, is the loop even running?
Low tech debugging, check that there are some Items in the combobox and that you are referencing the combo you intended :)
Ok this is strange, I managed to solve the problem by puting each loop on a separate method, and now it works, thanks for the help anyways!