I'm just wondering why the compiler gives me this error. The try block will be executed every time the function is called and that means the variable will get assigned. But still it doesn't let me compile.
using System;
namespace Checking
{
class Program
{
static void Main(string[] args)
{
int intNum;
intNum = readValue("Please enter a number: ");
}
static int readValue(string strPrompt)
{
int intRes;
Console.WriteLine(strPrompt);
try
{
intRes = Convert.ToInt32(Console.ReadLine()); // Gets assigned here! But still doesnt allow me to compile!
}
catch (Exception ex)
{
Console.WriteLine("Please enter a numeric value.\n");
readValue(strPrompt);
}
return intRes;
}
}
}
Putting return intRes inside the try block allows me to get rid of that error, but then an error crops up saying not all code paths return a value. I understand the errors, but I still don't understand why it won't allow me to compile, the try block gets executed every time right?
I also know that assigning 0 to intRes will get rid of that error.
Regards,
The compiler is right. The variable is not always assigned.
If the conversion fails, the assignment never happens, and the execution continues inside the catch block, where you call the function again, but you have forgotten to assign the return value of that call to the variable:
catch (Exception ex)
{
Console.WriteLine("Please enter a numeric value.\n");
intRes = readValue(strPrompt);
}
Here's an anternative implementation using a while and TryParse:
static int readValue(string strPrompt) {
int intRes = 0;
bool done = false;
while (!done) {
Console.WriteLine(strPrompt);
if (Int32.TryParse(Console.ReadLine(), out intRes) {
done = true;
} else {
Console.WriteLine("Please enter a numeric value.\n");
}
}
return intRes;
}
If Convert.ToInt32 failes, intRes never gets assigned to.
Either set a default value when creating the variable, or assign to in the catch block.
Because if the try fails, intRes has no value
In your catch use
intRes = readValue(strPrompt);
Initialise it with
int intRes = 0;
instead of
int intRes;
You may also want to look at the int.TryParse syntax
You will get an uninitialized intRes if Console.ReadLine() throws an exception. That is why your compiler is complaining.
The compiler has no way to know if your code inside the try block will throw an exception or not.
So, in case your code throws an exception, then the intRes variable will never be assigned.
Consequently the compiler emits the error message.
Also, as it stands, your code has a problem. You try to recursively call readValue inside the catch block to get a correct value but when your user finally enter a correct value, the main will never receive the value entered because you are using a local variable for the result value.
Related
Like if I had an else if or try catch statement. How can I stop specific lines of code from executing if the statement failed or caught an unhandled exception
I already posted the question before, so I'm just reformulating.
If you don't want the program to execute a certain line of code if the try catch fails, what would you do?
try
{
PRECIO = Convert.ToDouble(TBPRECIO.Text);
CANTIDAD = Convert.ToDouble(TBCANTIDAD.Text);
CATEGORIA = Convert.ToDouble(TBCATEGORIA.Text);
}
catch
{
MessageBox.Show("NO PUEDE HABER ESPACIOS VACIOS");
TBPRECIO.Focus();
}
I think the general solution to what you're asking is that you can declare a variable outside the try block and set it inside the try block after the line you want to check executes.
bool CANTIDADRead = false;
try
{
PRECIO = Convert.ToDouble(TBPRECIO.Text);
CANTIDAD = Convert.ToDouble(TBCANTIDAD.Text);
CANTIDADRead = true;
CATEGORIA = Convert.ToDouble(TBCATEGORIA.Text);
}
catch
{
MessageBox.Show("NO PUEDE HABER ESPACIOS VACIOS");
TBPRECIO.Focus();
}
if(CANTIDADRead)
//do stuff
In your particular case though, you might be better off switching to double.TryParse:
bool PRECIOREAD = double.TryParse(TBPRECIO.Text, out PRECIO);
bool CANTIDADREAD = double.TryParse(TBCANTIDAD.Text, out CANTIDAD);
bool CATEGORIAREAD = double.TryParse(TBCATEGORIA.Text, out CATEGORIA);
This will attempt to parse the value of those strings and return whether or not the parse is successful. The out keyword means that the variable you pass in will be updated by the method, but if the parse fails it won't be the correct value.
using System;
class MainClass {
public static void Main (string[] args) {
bool loop1 = true;
while(loop1)
{
Console.WriteLine("\nEnter the base length");
try
{
int length = Convert.ToInt32(Console.ReadLine());
}
catch (Exception ex)
{
Console.WriteLine("\nInvalid Entry: "+ex.Message);
continue;
}
Console.WriteLine("\nEnter the perpendicular height");
try
{
int length = Convert.ToInt32(Console.ReadLine());
}
catch (Exception ex)
{
Console.WriteLine("\nInvalid Entry: "+ex.Message);
}
Console.WriteLine(area(length,height));
}
}
static int area(int length, int height)
{
return length * height/2;
}
}
I get the error
exit status 1
main.cs(28,40): error CS0103: The name length' does not exist in the current context
main.cs(28,47): error CS0103: The nameheight' does not exist in the current context
Compilation failed: 2 error(s), 0 warnings
You're declaring the local variables length inside your try blocks; they only exist in that scope. Once execution leaves the try block, it doesn't exist anymore.
See https://msdn.microsoft.com/en-us/library/ms973875.aspx for more information about how scoping works in C#.
More specifically, when you call Console.WriteLine(area(length,height));, the variables length and height that you are trying to pass into the method do not exist in that scope. Declare them in that scope, rather than inside the try blocks.
You are declaring your variables inside the try, you need to move the declaration outside the try statement. I think this will fix it. Plus your declaring length twice, I think that was a typo and should have been height.
using System;
class MainClass {
public static void Main (string[] args) {
int length = 0;
int height = 0;
bool loop1 = true;
while(loop1)
{
Console.WriteLine("\nEnter the base length");
try
{
length = Convert.ToInt32(Console.ReadLine());
}
catch (Exception ex)
{
Console.WriteLine("\nInvalid Entry: "+ex.Message);
continue;
}
Console.WriteLine("\nEnter the perpendicular height");
try
{
height = Convert.ToInt32(Console.ReadLine());
}
catch (Exception ex)
{
Console.WriteLine("\nInvalid Entry: "+ex.Message);
}
Console.WriteLine(area(length,height));
}// end while
}// end main
static int area(int length, int height)
{
return length * height/2;
}
}// end calss
The reason for this error is your defined variable int length is scoped inside curly braces { }. So the variable is only available inside the brace it is defined.
To be able to access the variable as you want, you have to define length at the start outside try block.
Specifically addressing the "Use of unassigned local variable 'height'" message...
This normally happens if you try to reference a variable that has never been assigned a value. Something like the following will trigger this error message:
int x;
Console.WriteLine(x);
Does the "Use of unassigned local variable 'height'" message happen when you enter invalid input that can't be cast as an integer? Entering something like "x" or "1.5" for length will cause the Convert.ToInt32() call to throw an exception, meaning that your length variable will not have anything assigned to it when the call to Console.WriteLine(area(length,height)); happens later.
You can fix/prevent this by initializing your variable when they are declared:
int length = 0;
int height = 0;
Now the variables are initialized and you won't see the "Use of unassigned local variable 'height'" message. You'll probably get 0 as your calculated area, but that's a different issue entirely. :)
I'm making assumptions about your input, but that's the only way I can think of to replicate the error you're seeing.
I have a piece of code that sometimes throws an exception and sometimes doesn't. Depending on IO and network, different kinds of exception might be thrown. I have a wrapper for that code that shall retry the failing statement, say 10 times until it succeeds. If the exception does not go away after the 10th time, I rethrow it. Until now, I know what to do. Currently, I have something like this:
private void ExecuteStatement(Action statementToExecute)
{
while (true)
{
int exceptionCount = 0;
try
{
statementToExecute.Invoke();
// statement finished successfully
break;
}
catch (Exception e)
{
if (!IsFrameworkException(e))
throw; // rethrow as it isn't a framework exception
// we know now that it's a framework exception
exceptionCount++;
if (exceptionCount >= MaxRetriesOnFrameworkException)
throw;
}
}
}
The issue is the following: I want to reset the counter in case the exception changes (i. e. different type, different stacktrace, different message). I know how to compare them individually, but I want to know if there's a standard C# way of accomplishing this.
Edit: Here's the code of IsFrameworkException:
private bool IsFrameworkException(Exception e)
{
Exception rootCause = e.GetBaseException();
return rootCause.GetType() == typeof(WebException);
}
This is not specifically related to exception handling, but a simple way to keep counters by a specific key is to use a Tuple as the key (it implements equality by value out of the box).
Note that this doesn't reset the counter on key change, it justs keeps separate counters for each key:
readonly Dictionary<Tuple<Type, string, string>, int> _counters =
new Dictionary<Tuple<Type, string, string>, int>();
bool IsCountExceeded(Exception ex)
{
// create your key with whatever properties you consider to
// be "unique"
var key = Tuple.Create(ex.GetType(), ex.StackTrace, ex.Message);
// increase counter
int counter;
if (!_counters.TryGetValue(key, out counter))
{
counter = 1;
}
else
{
counter++;
}
_counters[key] = counter;
return counter > Max;
}
You can of course always make it more readable by creating your own class, which will implement Equals/GetHashCode properly.
I am also not sure that the stack trace can be considered as a unique property, and of course, catching and ignoring exceptions is usually a bad idea.
You should specify the exception type you want to catch. Place the catch blocks in order of most specific type to most generic type.
It is not clear if the exceptions all derive from FrameworkException or if you want to use Exception, the following assumes the former.
int exceptionCount = 0;
Type lastCaughtException = null;
while(true) {
try
{
statementToExecute.Invoke();
// statement finished successfully
break;
}
catch (WebException ex)
{
if(lastCaughtException == null || lastCaughtException != ex.GetType())
exceptionCount = 0;
else
exceptionCount++;
lastCaughtException = ex.GetType();
if (exceptionCount >= MaxRetriesOnFrameworkException)
throw;
}
catch (Exception) // if you do not want to log this you can completely omit this catch
{
throw; // rethrow as it isn't a framework exception
}
}
See also try-catch (C# Reference)
What happens here ?
I wonder whether SaveError() can be called after exception block ?
Does the Main.cs get noticed about caught error?
I want to see the story behind this case.
What is the value of the variable "a" ?
note: Asume there has been an error in try block.
Main.Cs
public void RunAll()
{
....
int a = doSubTask();
}
A.cs
public int doSubTask(){
try{
..
..
return 1;
}catch(Exception Ex)
{
throw new AppException("Error", ex);
}
finally
{
SaveError();
return -1;
}
return 0;
}
The return 0; after the finally is redundant since finally will be called always even if there was an exception inside the cache or not.
Anyway, leaving the finally block with return will cause you a compilation error which means in your case, since you are throwing an exception from inside the catch block, a will not be set by any value.
First of all, you can't return value within finally block, C# does not allow this.
finally always executes even if there are errors (i.e. control goes in catch block). So in your case, the return value will always be -1, it does not matter whether exception was thrown or not.
The last statement return 0; is non-reachable.
I guess you can modify your code like this. You shouldn't use more than one "return" key in a method.
public int doSubTask()
{
int retval = 0;
try
{
//to do
retval = 1;
}
catch (Exception Ex)
{
SaveError();
retval = -1;
throw new AppException("Error", ex);
}
finally
{
// do something even there is error or not
}
return retval;
}
Short answer: it depends from you machine ^^
As you can see in this MSDN article: http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ,
if the exception is unhandled it's up to your system to decide if the Finally statement is executed or not.
Also: you can't return a value in a finally statement.
The whole method Foo seems a bit confusing to me.
If your goal is to try a "risky" operation and handle the error you shouldn't rethrow the exception without having the outer code handle that.
So, if you want the RunAll method to know if there's been an error, you should set it's code inside a try-catch statement and rethrow the exception in the Foo method, without the finally statement so the rethrown exception "bubbles up" the chain and gets handled in the calling method :)
It is not allowed to try to "leave" a finally block, so it will not be valid to say return -1; inside the finally block. So your code will never compile.
error CS0157: Control cannot leave the body of a finally clause
Hence, there exists no question "what will happen when it runs".
Consider,
static void Main(string[] args)
{
Console.WriteLine(fun());
}
static int fun()
{
int i = 0;
try
{
i = 1;
return i;
}
catch (Exception ex)
{
i = 2;
return i;
}
finally
{
i = 3;
}
}
The sample code outputs "1". but the value of i is changed to 3 in finally block. Why wasn't the value of 'i' changed to 3?
Thank you,
Consider this code- I think the code explains what you are thinking, and how you can make what you think should happen actually happen:
static void Main(string[] args)
{
int counter = 0;
Console.WriteLine(fun(ref counter)); // Prints 1
Console.WriteLine(counter); // Prints 3
}
static int fun(ref int counter)
{
try
{
counter = 1;
return counter;
}
finally
{
counter = 3;
}
}
With this code you return 1 from the method, but you also set the counter variable to 3, which you can access from outside the method.
You have to remember that finally executes after everything else in the try and catch. Place the return statement after the try/catch/finally statement to have it return 3.
I imagine if you use a reference type instead of a value type you'd get different behavior.
When you said "return i"... C# puts that return value in a temporary holding area (memory) and then runs your 'finally' code... if the finally block was able to modify that value, it would defeat the safety/finalism of the finally block.
It's like a using statement with a return inside... the "Dispose" is still going to happen, AFTER the return (so to speak).
Finally is always executed
Your code always executes finally no matter if an exception was thrown or not. So your code should actually be:
try
{
i = 1;
}
catch
{
i = 2;
}
finally
{
i = 3;
}
return i;
But in this trivial case finally block won't make much sense. Because we will always return 3 no matter what happened before that.
Finally is used to release resources
finally block should normally be used when you have to release some system resources allocated within try block (ie. openning a DB connection an reading data in try block and closing it in finally). So they will always get released no matter if there was an exception or not. In this case it doesn't make much sense to use finally block.