I have a method that i have to call it from itself for multiple times in order to get a result and i want to know is Recursive call work as goto in this situation ?
Dummy Code:
public int DummyMethod()
{
string token;
int result = -1;
token = GetNewToken();
Stopwatch stopwatch = Stopwatch.StartNew();
while (result == -1)
{
if (stopwatch.Elapsed >= TimeSpan.FromSeconds(350)) {
//This is related to some logic as the token for the website
//expires after 350 seconds.
result = DummyMethod();
continue; //DO I NEED TO USE contunue ? or the recursive
//call broke the method (as if i used goto)
}
result = GetResultFromWebSite(token);
}
return result;
}
I think you have this all wrong and you definitely shouldn't be trying to figure out if your token has expired. This should be something the server tells you. If it comes via an exception you could do something like this:
public int DummyMethod(int retries = 0)
{
string token;
try
{
token = GetNewToken();
return GetResultFromWebSite(token);
}
catch (Exception e)
{
if (retries < 4) // or whatever max you want - you probably shouldn't hardcode it
{
return DummyMethod(++retries);
}
throw new Exception("Server ain't responding");
}
}
In a situation like this, it's often a good idea to have a maximum number of retries after which you will give up and show an error message.
You should instead use
return DummyMethod();
which is a tail call (the compiler can turn it into a goto).
This is a good illustration of one way the "single entry/single return" mantra fails.
However, I'm pretty sure you could just build this into the loop and avoid recursion:
public int DummyMethod()
{
Stopwatch stopwatch = Stopwatch.StartNew();
string token = GetNewToken();
int result;
do
{
if (stopwatch.Elapsed.TotalSeconds >= 350) {
token = GetNewToken();
stopwatch.Restart();
}
result = GetResultFromWebSite(token);
} while (result == -1);
return result;
}
It seems to me that you want to know how to stop the recursion. This is normally done with a condition where the result is clear and returned without calling the recursive function again. This way the endless calling of the recursive method is stopped and the recursion will come to an end. You dont use a goto for that like you simply never should use goto ;)
No, recursive calls are not equivalent to goto statements.
You don't even need to use recursion to solve your problem. If you place your call to GetNewToken in the loop, you can check the result and use continue to perform another iteration if you don't get the desired results. If you do get the desired result, you can call GetResultFromWebSite and return its result immediately.
Related
Could anyone help me out by providing the solution through Recursive Methods
My Requirement is I want a recursive method, that needs to run the below code three times:
Below is my C# Working Code :
public void Process()
{
bool exists = File.Exists("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\RevisionNumber.txt");
for(int i = 0; i < 3 && exists; i++)
{
System.Diagnostics.Process.Start("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\SvnUninstallation.exe");
Sleep(2000); // or long enough to ensure the uninstall process finishes executing
exists = File.Exists("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\RevisionNumber.txt");
}
Console.WriteLine(exists);
Console.ReadLine();
}
Your original code, with the for loop, does exactly what your recursive function will do. I am not too happy with posting this code. The only valid time I could think of using a recursive function, is when you are building up a Tree structure of some sorts.
You should also be aware, if you do not implement a recursive function properly, and you do not break the continuous loop you might create using recursive functions, you will run into an StackOverflow exception, due to your method being called is added to the stack, and the stack will eventually run out of memory.
Here is one way of implementing a recursive function for your needs:
public void Process(int count = 0)
{
bool exists = File.Exists("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\RevisionNumber.txt");
if (exists && count < 3)
{
System.Diagnostics.Process.Start("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\SvnUninstallation.exe");
Thread.Sleep(2000); // or long enough to ensure the uninstall process finishes executing
//File exists
Console.WriteLine("File exists");
Process(++count);
}
else
{
Console.WriteLine("Exceeded retry of 3 times. File did not uninstall.");
}
if (!exists)
Console.WriteLine("File uninstalled");
}
Here is the code snippet for Recursive Method. Try it and let me know if you have any queries.
static bool FileExists(bool _fileexists, int Count)
{
//Console.WriteLine("Inside File Check");
Count++;
System.Diagnostics.Process.Start("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\SvnUninstallation.exe");
Thread.Sleep(2000);
return (_fileexists == false && Count <=3) ? FileExists(File.Exists("C:\\IFRToolLog1.txt"),Count) : true;
}
Related to this question
Suppose I have a long method which I want to abort on certain conditions. What's the best way to do this? Here are two ways I can think of.
try
{
// if i is 0, we don't want to continue
int i = testi();
if(i == 0)
throw new StopException("stop")
// the rest of our code
}
catch(StopException stop)
{
// handle our stop exception
}
catch{
// everything else
}
Here's another
bool go = true
while(go)
{
// if i is 0, we don't want to continue
int i = testi();
if(i == 0)
{
go = false;
break;
}
// the rest of our code
}
Both of these seem clunky. Throwing an exception seems like overkill, and I don't actually want to loop anything so while is being misused. It seems to me there should be (and probably is) a more elegant way of doing this in C#?
RETURN!
Doy. I have actually used this lots of times, for some reason it just popped out of my head today. Thanks for indulging me in my stupidity
The standard way to interrupt a C# method is by simply using the return statement.
if method is void simply return, if not then return null or return 0 depends on the case.
definitely no need to throw and exception just instead of a return.
Just exit the method using the return statement.
void longMethod()
{
int i = testi();
if(i == 0)
return;
// Continue with method
}
I want my code to keep trying a method until no exception is thrown, however, unlike this question, I would like it to be written as a generic method capable of running any input delegate/method. Here is what I've had in mind, but I am not sure how to pass the arguments or generic methods through it:
public void tryLoop(Delegate anyMethod, T[] arguments) {
while (true) {
// Could be replaced by timer timeout
try {
anyMethod(arguments);
break;
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
Is this possible?
EDIT: For the academics of it, I would also be curious to know if it's possible to return the result as well.
If you can settle for using closures, you won't need to have to pass parameters to this method all (or have multiple overloads). The result can be returned using a Func.
public T tryLoop<T>(Func<T> anyMethod)
{
while (true)
{
try
{
return anyMethod();
}
catch
{
System.Threading.Thread.Sleep(2000); // *
}
}
return default(T);
}
void SomeMethod(int param)
{
var someLocal = "Hi";
var anotherLocal = 0;
var result = tryLoop(() =>
{
Console.WriteLine(someLocal);
return param + anotherLocal;
});
Console.Write(result);
}
To be honest, I wouldn't set an infinite retry, however - at best, if certain types of retryable error were returned, such as a database deadlock, or a timeout calling an erratic web service, then possibly 3 or 4 retries might be in order. Exceptions such DivideByZero or FileNotFound aren't likely to go away by running them indefinitely :-)
*** especially with deadlocks, sleeping for a random period is recommended, just in case other threads are also simultaneously deadlocking on exactly the same data - you don't want the same deadlock recurrence happening in 2000ms :-).
A way to do this is by using an Action, and remove the arguments parameter:
public void tryLoop(Action anyMethod) {
while ( true ) {
// Could be replaced by timer timeout
try {
anyMethod();
break;
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
This gives you ultimate freedom in how to use it:
tryLoop(() => string.Reverse("abc"));
or like this:
String s1 = "A";
String s2 = "b";
tryLoop(() => string.Concat(s1, s2));
As you can see in the second example, you can directly take the arguments from the context of the tryLoop method being called. You can invoke anything there.
The good thing for this approach is that you will not have to use Invoke or DynamicInvoke as with a Delegate instead of Action, because these introduce a performance penalty.
If you need the result, you can re-write the above with a Func<T> instead of Action, like this:
public T tryLoop<T>(Func<T> anyMethod) {
while ( true ) {
// Could be replaced by timer timeout
try {
return anyMethod();
}
catch {
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
and use it like this:
var reversed = tryLoop(() => string.Reverse("abc"));
String s1 = "A";
String s2 = "b";
var concatenated = tryLoop(() => string.Concat(s1, s2));
Check if this suit your needs. If not then please comment. Also not sure how it will be performance wise.
Also the DynamicInvoke method has an object return type. This you can use to return the result of the delegate. You can change the return type of method from void to object.
public void tryLoop<T>(Delegate anyMethod, T[] arguments)
{
while (true)
{ // Could be replaced by timer timeout
try
{
anyMethod.DynamicInvoke(arguments);
break;
}
catch
{
System.Threading.Thread.Sleep(2000); // wait 2 seconds
}
}
}
Hope this helps
I'm new to C# and while coding a small function facing this weird problem. While using the return statement I want to return to the calling function but instead it takes me to a level before in the recursion and never exits from the recursive function.
My code is as follows:
private void findrel(String from, String to, List<RelAttr> relation)
{
String var;
List<RelAttr> temp = new List<RelAttr>();
for (int i = 0; i < relation.Count; i++)
{
if (Some Condition)
{
if (Another Condition)
{
//Do Something
paths.Add(Something);
return;
}
else
{
//Capture some value in var
paths.Add(Something);
//Move to Temp
temp.AddRange(relation);
//Remove Active Entry From Temp
temp.RemoveAt(i);
//Call with Newlist (temp)
findrel(var, to, temp);
}
}
}
//Remove Last Entry when recursion unwinds
paths.RemoveAt(paths.Count - 1);
}
I'm calling this function normally from the other function such as:
findrel(from, to, relations);
And I want the return statement to return to this function and not to a level before in the recursion. Any ideas?
The return statement will always return to the caller, and when you are using recursion this will include returning to the level above, and will not jump back to the original caller.
If you want to get right out of findrel then you will have to do something like return a flag so that the previous level knows that it should just return back to its caller and not do any more processing.
So the code will still unwind from all the calls to findrel but you will have effectively stopped processing.
Usually with recursive functions you have a terminating condition and that causes all levels of the returning function to return and this will return you to the caller. One suggestion might be to return a Boolean and terminate the recursion if that value is say false. The you can add that condition to the terminating condition of your loop and your function will exit all levels.
I have a class that tries to get information from web service few times:
public TResult Try(Func<TResult> func, int maxRetries)
{
TResult returnValue = default(TResult);
int numTries = 0;
bool succeeded = false;
while (numTries < maxRetries)
{
try
{
returnValue = func();
succeeded = true;
}
catch (Exception ex)
{
Log(ex,numTries);
}
finally
{
numTries++;
}
if (succeeded)
{
return returnValue;
}
else
{
if (numTries == maxRetries)
{
//ask user what to do
}
}
}
Now after 'if (numTries == maxRetries)' user will be able to chose if he wants to continue trying to get data from web service or cancel.
I want to just open new form when user cancels and stop executing method that called above method. I can't just return null or new object because the method that run this retrier will continue to work and in many cases cause problems.
So basically this looks like this:
someValue = retry.Try(() => webService.method(),maxRetries));
//if user canceled after app wasn't able to get data stop execution as already another form is opened
I could of course check if returned value was null like:
someValue = retry.Try(()=>webService.method(),maxRetries));
if (someValue == null)
return;
But this would mean a lot of changes in the code and I want to avoid it and it would be best if I could do it from Try method.
I can think of two things. You could make sure that TResult is of an Interface type that has a Boolean field that represents a successful request (IsSuccessful or IsValid, etc). If you cannot modify TResult, the other option is to use an Out parameter on your try method to pass another value out.
There is no way to just stop the execution of a method. The first thing that comes to mind though is to throw an exception and catch it from the calling method.
Keep in mind though that you shouldn't ever rely on exceptions to control flow like that.. but if you really can't rewrite the calling method, this may be your only option.
The other option is perhaps having your returned result set a flag (via an interface) to notify the caller that it completed successfully.