I've different thread which contains an infinite loop, inside each loop I call this method that return a true or false based on specific condition, but I'm going to return true just for example:
public void Test()
{
return true;
}
I'm wondering if can I break or continue the execution of the loop in a quick way, I mean, without write in any loop this condition:
if(Test())
{
break;
}
If I catch your meaning, you probably want to do the work while Test() is not returning false:
do
{
//your stuff
} while (Test());
Or if you won't necessarily iterate even once:
while(Test())
{
//your stuff
}
Related
Basically, I want to break the method if it's on cooldown. But when I move the if statement inside a method, it will not work. The return keyword will just return to the previous method and continue the rest.
Is there any way to do it?
Let the CooldownCheck method return the stop status, e.g., through a Boolean:
public void Interact()
{
if (CooldownCheck()) {
InInteract.Invoke();
lastCooled = Time.time + cooldown;
}
}
private bool CooldownCheck()
{
if (lastCooled <= Time.time) {
Debug.Log(stuff);
return true;
}
return false;
}
Btw., your else { return; } makes no sense, as any void method has an implicit return; at its end. The return-statement does not stop anything, it returns from the method, i.e., it leaves the method at this point and continues to run the caller, i.e., the caller will then execute the next statement.
A way to interrupt the caller would be to throw an exception. But this seems not appropriate in this case.
I have a validation method which I call in a loop.
I want to call "continue" if the validation fails.
Is there a way to call "continue" from the validation method ?
I just don't want to call "continue" in so many places in the loop...
No, flow control statements only affect the blocks within which they are defined. The only built-in way to alter control flow from further up the stack like that is an exception, which is definitely the wrong mechanism for what you are doing.
If you are bothered by all the continues, I suggest you consider moving towards a more declarative way of thinking. Define the body of your validation loop like so:
bool IsValid(Foo foo) {
if (Condition1(foo)) {
return false;
}
if (Condition2(foo)) {
return false;
}
// ... and so on
}
and then validate like this:
if (!foos.All(IsValid)) {
// One of your foos is invalid
}
the LINQ extension methods All and Any will break execution as soon as they can, meaning that All will stop when it finds the first one that doesn't satisfy the condition and Any will stop when it finds the first one that does.
You have a lot of continues in your cycle and it becomes bothering. You cannot continue from the external method, as it is out of scope. There are several solutions actually though:
You can return a boolean value from your validation methods and then use it as such:
if (!IsValid()) {
continue;
}
It is not helpful though, because you will still have continues.
You can put your validations at the start of the cycle and you can use a flag to determine whether the iteration should step out, initialized by false:
while (myCondition) {
stepOut = false;
//validation region, you set stepOut to false if a validation fails
if (!stepOut) {
//operations
}
}
You can wrap all the validation call into a method, let's call it myValidation and then:
while (myCondition) {
if (myValidation()) {
//operations
}
}
or
while (myCondition) {
if (!IsValid()) {
//continue
}
}
You can throw an Exception, but DON'T do that.
Just return false in your validation method wherever it should return, then check if the validation method returns false, break out of loop in caller function.
Why Not ?
Golden Rule in Programming : "There is always a way".
C++ lets you inline Assembly Language syntax. Similar to it, C# supports it too. Let me consider your example.
void method1(){
foreach(var x in y)
{
Validate(x);
...
//Your other logic
...
EndOfLoop:
;
}
}
..
..
void Validate(T x)
{
#if IL
br EndOfLoop
#endif
}
//End Of Code
This will "jump" to the "EndOfLoop" Label from anywhere within your Code. This could be a bad practice depending on your code though..
Hi I want to stop the execution of if-loop ,I have tried with 'return' statement but its exits from the function ,So how can I exit from the single if Statement.I have tried with following code...
Here I want to stop execution of if(CheckHorizontalSide(SourceMember)) and by stopping this I want to move towards the if(CheckTop(SourceMember))
void A()
{
if (CheckHorizontalSide(SourceMember))
{
if (lblHorizontalMember.Text == DestinationMember)
{
lsRelationPath.Add(lblHorizontalMember.Text);
lblRelationPath.Text = String.Join("-", lsRelationPath);
lblRelationPath.Visible = true;
return;
}
bool WhetherContains = lsRelationPath.Contains(SourceMember);
if (WhetherContains)
{
return;
}
//This below code is not related to the above 'WhetherContains '
lsMemberID1.Clear();
lsRelationPath.Add(lblHorizontalMember.Text);
Find_Route(lblHorizontalMember.Text, DestinationMember);
}
if(CheckTop(SourceMember))
{
//code here....
}
}
You put the rest of the block in a sub-block with { } and put else in front of that.
You can nest as deeply as you want but you might try factoring out blocks to helper functions to reduce the complexity and give statements a name.
if (WhetherContains)
{
// this is actually empty
}
else
{
lsMemberID1.Clear();
lsRelationPath.Add(lblHorizontalMember.Text);
}
Or,
if (!WhetherContains)
{
lsMemberID1.Clear();
lsRelationPath.Add(lblHorizontalMember.Text);
}
I've a multi-threading issue.
I've a method that is called to make refresh on several items.
In this method, I iterate on a list of items and refresh one of it's property.
The list has a lot of elements and we have to do some math to compute it's property.
The current code of this operation look like this:
public void AddItemsWithLayoutRefresh(IEnumerable<MyItem> items){
_control.Invoke(()=>{
AddItems(items);
for(int i =0;i<_guiItems.Count;i++){
//The goal is to have a condition here to "break" the loop and let the next call to RefreshLayout proceed
_guiItems[i].Propriety = ComputePropriety(_guiItems[i]);
}
});
}
The problem is that I may have 4 call, which are currently just blocking on the Invoke.
I've to finish the "AddItems" methods, but concerning everything that is in the "for" loop, I can abort this without any issue if I know that it will be executed just after.
But how to do this in a thread-safe way?
If I put a private bool _isNewRefreshHere;, set to true before entering the Invoke, then checking in the Invoke, I've no warranty that there is not already two call that have reach the Invoke BEFORE I check it in the for loop.
So how can I break when being in my loop when a new call is made to my method?
Solution
Based on Andrej Mohar's answer, I did the following:
private long m_refreshQueryCount;
public void AddItemsWithLayoutRefresh(IEnumerable<MyItem> items){
Interlocked.Increment(ref m_refreshQueryCount);
_control.Invoke(()=>{
Interlocked.Decrement(ref m_refreshQueryCount);
AddItems(items);
for(int i =0;i<_guiItems.Count;i++){
if (Interlocked.Read(ref m_refreshQueryCount) > 0)
{
break;
}
_guiItems[i].Propriety = ComputePropriety(_guiItems[i]);
}
});
}
Which seems to work very nicely
If I were you, I'd try to make a thread-safe waiting counter. You can use Interlocked methods like Increment and Decrement. What these basically do is they increment the value as an atomic operation, which is considered to be thread-safe. So you increase the variable before the Invoke call. This will allow you to know how many threads are in the waiting queue. You decrement the variable after the for loop finishes and before the ending of the Invoke block. You can then check inside the for statement for the number of waiting threads and break the for if the number is greater than 1. This way you should know exactly how many threads are in the execution chain.
I would do it in the following way:
private readonly object _refresherLock = new object();
private bool _isNewRefreshHere = false;
private AutoResetEvent _refresher = new AutoResetEvent(true);
public void AddItemsWithLayoutRefresh(IEnumerable<MyItem> items)
{
lock (_refresherLock)
{
if (_isNewRefreshHere)
{
return;
}
_isNewRefreshHere = true;
}
_refresher.WaitOne();
_isNewRefreshHere = false;
_control.Invoke(() =>
{
AddItems(items);
for (int i = 0; i < _guiItems.Count && !_isNewRefreshHere; i++)
{
_guiItems[i].Propriety = ComputePropriety(_guiItems[i]);
}
_refresher.Set();
});
}
That is:
You can always cancel the current updation with a new one.
You cannot queue up more than one updation at a time.
You are guaranteed to have no cross-threading conflicts.
You should test that code since I did not. :)
What if I have nested loops, and I want to break out of all of them at once?
while (true) {
// ...
while (shouldCont) {
// ...
while (shouldGo) {
// ...
if (timeToStop) {
break; // Break out of everything?
}
}
}
}
In PHP, break takes an argument for the number of loops to break out of. Can something like this be done in C#?
What about something hideous, like goto?
// In the innermost loop
goto BREAK
// ...
BREAK: break; break; break;
Extract your nested loops into a function and then you can use return to get out of the loop from anywhere, rather than break.
Introduce another control flag and put it in all your nested while condition like below. Also replaces the while(true) condition you have with that
bool keepLooping = true;
while (keepLooping) {
// ...
while (shouldCont && keepLooping) {
// ...
while (shouldGo && keepLooping) {
// ...
if (timeToStop) {
keepLooping = false;
break; // break out of everything?
}
}
}
}
Goto is only hideous when abused. To drop out of the innermost loop of some nesting it's acceptable. BUT... one has to ask why there is so much nesting there in the first place.
Short answer: No.
If you want to break out of an entire method, then use the code below.
If you only want to break out of a series of loops within a method without breaking out of the method, then one of the answers that have already been posted will do the job.
if (TimeToStop)
{
return;
}
You can just use goto to get out of the loops:
[...]
while (true) {
// ...
while (shouldCont) {
// ...
while (shouldGo) {
// ...
if (timeToStop) {
goto GETOUT;
}
}
}
}
GETOUT:
//move on to the next step
[...]