Yield return and exception handling [duplicate] - c#

This question already has answers here:
Why does this string extension method not throw an exception?
(3 answers)
Closed 7 years ago.
I just had a case with a method using yield return not throwing an ArgumentException which I expected. I have reconstructed the case with the simpliest possible classes here:
class Program
{
static void Main(string[] args)
{
try
{
var listA = FooA(count: 0);
Console.WriteLine("A did not throw exception!");
}
catch (ArgumentException)
{
Console.WriteLine("A threw exception!");
}
try
{
var listB = FooB(count: 0);
Console.WriteLine("B did not throw exception!");
}
catch (ArgumentException)
{
Console.WriteLine("B threw exception!");
}
Console.ReadLine();
}
private static IEnumerable<int> FooA(int count)
{
if(count == 0)
throw new ArgumentException("Count must be above 0");
var list = new List<int>();
for (var i = 0; i < count; i++)
{
list.Add(i);
}
return list;
}
private static IEnumerable<int> FooB(int count)
{
if (count == 0)
throw new ArgumentException("Count must be above 0");
for (var i = 0; i < count; i++)
{
yield return i;
}
}
}
Output:
A threw exception!
B did not throw exception!
Can some one please explain to me why FooB does not throw an exception while FooA does?

It's because FooB is never even evaluated.
When you call a method, that method is called immediately. When you use yield and return an enumerable, that method is only called when something needs to use the value returned, and only a single item at a time; this is the benefit of yielding.
So, if you add something that uses the value
try
{
var listB = FooB(count: 0);
Console.WriteLine(listB.First()); // use the IEnumerable returned
Console.WriteLine("B did not throw exception!");
}
catch (ArgumentException)
{
Console.WriteLine("B threw exception!");
}
You will see your expected result.

Related

Loop to repeat a method 3 times if condition fails

Im looking for a simple way, to repeat a method, when an element(selector) for example a button on a webpage cant be found.
My idea or my plan is, that:
If the selector can be found, the method is done
If the selector cant be found, it should repeat the "FindElement" method up to maximal 3 times
If the selector cant be found after the third try, it should give me an output message of the "NoSuchElementException e"
I tried different loops and i always end up having endless loops like in the code below.
public static void FindElement(IWebDriver webDriver, string selector)
{
int maxTries = 0;
try
{
webDriver.FindElement(By.XPath(selector));
Console.WriteLine("Element found.");
}
catch (NoSuchElementException e)
{
if (maxTries !> 3 )
{
Console.WriteLine("Element, not found. Retrying.");
maxTries++;
FindElement(webDriver, selector);
}
else
{
Console.WriteLine(e);
}
}
}
What a coincidence: Just a few days ago I wrote a short helper method to separate "retry logic" from "business logic".
private T Retry<T>(Func<T> action, int maxRetryCount, int waitMilliseconds,
Func<Exception, bool> retryCondition)
{
var retryCount = 0;
while (true)
{
try
{
// If the action was successful (no exception thrown),
// we can leave the method.
return action();
}
catch (Exception ex) when (retryCount < maxRetryCount && retryCondition(ex))
{
retryCount += 1;
Thread.Sleep(waitMilliseconds);
}
}
}
Which would be called as follows in your case:
var element = Retry(() => webDriver.FindElement(By.XPath(selector)),
2, 0,
ex => ex is NoSuchElementException);
Whenever the maximum number of retries is reached, the exception is not caught any more (the when condition fails) and can be caught by your regular exception handling logic instead.
Since you are trying to automate a web browser, you might consider passing something else than 0 as waitMilliseconds, to give the browser time to render the elements that are still missing.
Why don't you put the maxTry outside of your function?
int maxTry=3;
string errorMessage="";
for(int i=0;i<maxTry;i++)
{
try
{
FindElement(webDriver,selector)
errorMessage="";
break;
}
catch (NoSuchElementException e)
{
errorMessage=e;
}
}
if(errorMessage!="")
{
Console.WriteLine(e);
}
else
{
Console.WriteLine("Element found.");
}
For recursion, you should pass the amount of remaining iterations to the function, and decrement it for each iteration.
public static void FindElement(IWebDriver webDriver, string selector, int iterations = 3)
{
iterations--;
if (iterations < 0)
{
Console.WriteLine("Max iterations passed, exiting")
return;
}
try
{
webDriver.FindElement(By.XPath(selector));
Console.WriteLine("Element found.");
}
catch (NoSuchElementException e)
{
Console.WriteLine("Element not found. Retrying.");
FindElement(webDriver, selector, iterations);
}
}

Rethrow exception in for loop

I want to create a method to retry some code with wait when exception occur. How can I get rid of that last exception?
public static T TryWithWait<T>(Func<T> func, int tries, TimeSpan exceptionSleep)
{
if (tries < 1)
throw new Exception("Tries amount cannot be < 1");
for (int i = 0; i < tries; i++)
{
try
{
return func.Invoke();
}
catch
{
if (i == (tries - 1))
throw;
else
Thread.Sleep(exceptionSleep);
}
}
throw new Exception("Code wouldn't compile without that");
}
You can use recursivity !
public static T TryWithWait<T>(Func<T> func, int tries, TimeSpan exceptionSleep, Exception innerException = null)
{
// You must to knows what exception was generated, I put it as InnerException
if (tries < 1) throw new Exception("Tries amount cannot be < 1", innerException);
try
{
return func.Invoke();
}
catch(Exception exception)
{
return TryWithWait(func, --tries, exceptionSleep, exception);
}
}

try catch over IEnumerable is not working as expected [duplicate]

This question already has answers here:
Why does this string extension method not throw an exception?
(3 answers)
Closed 7 years ago.
I just had a case with a method using yield return not throwing an ArgumentException which I expected. I have reconstructed the case with the simpliest possible classes here:
class Program
{
static void Main(string[] args)
{
try
{
var listA = FooA(count: 0);
Console.WriteLine("A did not throw exception!");
}
catch (ArgumentException)
{
Console.WriteLine("A threw exception!");
}
try
{
var listB = FooB(count: 0);
Console.WriteLine("B did not throw exception!");
}
catch (ArgumentException)
{
Console.WriteLine("B threw exception!");
}
Console.ReadLine();
}
private static IEnumerable<int> FooA(int count)
{
if(count == 0)
throw new ArgumentException("Count must be above 0");
var list = new List<int>();
for (var i = 0; i < count; i++)
{
list.Add(i);
}
return list;
}
private static IEnumerable<int> FooB(int count)
{
if (count == 0)
throw new ArgumentException("Count must be above 0");
for (var i = 0; i < count; i++)
{
yield return i;
}
}
}
Output:
A threw exception!
B did not throw exception!
Can some one please explain to me why FooB does not throw an exception while FooA does?
It's because FooB is never even evaluated.
When you call a method, that method is called immediately. When you use yield and return an enumerable, that method is only called when something needs to use the value returned, and only a single item at a time; this is the benefit of yielding.
So, if you add something that uses the value
try
{
var listB = FooB(count: 0);
Console.WriteLine(listB.First()); // use the IEnumerable returned
Console.WriteLine("B did not throw exception!");
}
catch (ArgumentException)
{
Console.WriteLine("B threw exception!");
}
You will see your expected result.

Why does my Test not pass for passing a null List? [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
I am working in C# building a form application. I have a method that takes in a type of List and returns a hashtable. I am trying to throw an argument exception if the the list is null. My program works the way it should and returns the results I need.
This is the error
Message: Expected: <System.Exception>
But was: <System.NullReferenceException: Object reference not set to an instance of an object.
at WordOccurenceCalculator.WordCalculator.CalculateOccurrences(List`1 List)
public void CalculateOccurrencesShouldThrowException() {
List<string> list = null;
WordCalculator calc = new WordCalculator();
Assert.Throws<Exception>(delegate { calc.CalculateOccurrences(list); });
}
public Hashtable CalculateOccurrences(List<string> List)
{
if ( List.Count == 0)
{
throw new System.ArgumentException("Invalid Input");
}
if (List == null)
{
throw new System.ArgumentException("Invalid Input");
}
Hashtable table = new Hashtable();
int counter = 1;
int j = 1;
for (int i = 0; i < List.Count; i++)
{
for(j = i + 1 ; j <= List.Count; j++)
{
if(j < List.Count){
if (List[i] == List[j])
{
counter++;
}
}
}
if (!table.Contains(List[i]))
{
table.Add(List[i], counter);
}
counter = 1;
}
return table;
}
you are checking null after trying to access count property of null list. You would get exception from there too. Try the bellow.
if (List == null)
{
throw new System.ArgumentException("Invalid Input");
}
if ( List.Count == 0)
{
throw new System.ArgumentException("Invalid Input");
}

Problems with the exceptions of the substitution derivative method

I'm trying to understand System.Exception class and I got some problems with override function. I try to intercept exception of DivideByZero and Write my user message which I generate in function of derivative class from System.Exception. this is my code:
public class zeroDivision
{
public void Deleter()
{
double z; int i = 0;
try
{
z = 10 / i;
Console.WriteLine("N={0} i={1} Result={2}", 10, i, z);
}
catch (zeroMessage e) **<====problem here: DivideByZeroException**
{
Console.WriteLine("N={0} i={1} Result={2}", 10, i, e.Message);
}
}
}
public class zeroMessage : System.Exception <--here debugger even doesn't come
{
public override string Message
{
get
{
string msg = base.Message;
msg = "Деление на ноль ЗАПРЕЩЕНО!!!";
return msg;
}
}
}
class Program
{
static void Main(string[] args)
{
zeroDivision zero = new zeroDivision();
zero.Deleter();
Console.Read();
}
}
When I call: catch(zeroMessage e) - it unhandled, but if I call: catch(Exception e) - it works. Where is my fault? I don't understand
-------------------------------
After some help of forum's masters, I remade this task with working functions. Maybe it will be useful for anybody:
public class zeroDivision
{
public void Deleter() //First way
{
double z; int i = 0;
try
{
z = 10 / i;
Console.WriteLine("N={0} i={1} Result={2}", 10, i, z);
}
catch (DivideByZeroException)
{
Console.WriteLine("N={0} i={1} Result={2}", 10, i, "Делить на ноль НИЗЗЯ!!!");
}
}
public double Deleter2(int a, int b) //Second way
{
if (b == 0) throw new zeroMessage();
return a / b;
}
public void prn(int i, int j) //Third way
{
try
{
Console.WriteLine(Deleter2(i, j));
}
catch (zeroMessage z)
{
Console.WriteLine(z.Message);
}
}
public void firstDeleter() //Updated Yesterday's code - Forth way
{
double z; int i = 0;
try
{
if (i == 0) throw new zeroMessage(); //!!!
z = 10 / i;
Console.WriteLine("N={0} i={1} Result={2}", 10, i, z);
}
catch (zeroMessage e)
{
Console.WriteLine("N={0} i={1} Result={2}", 10, i, e.Message);
}
}
}
public class zeroMessage : System.Exception
{
public override string Message
{
get
{
string msg = base.Message;
msg = "Деление на ноль ЗАПРЕЩЕНО!!!";
return msg;
}
}
}
class Program
{
static void Main(string[] args)
{
zeroDivision zero = new zeroDivision();
zero.Deleter();
try
{
double result = zero.Deleter2(10, 0);
Console.WriteLine(result);
}
catch (zeroMessage z)
{
Console.WriteLine(z.Message);
}
zeroDivision zero1 = new zeroDivision();
zero1.prn(10, 0);
zeroDivision zero2 = new zeroDivision();
zero2.firstDeleter();
Console.Read();
}
}
When you are trying to divide CLR throws the exception of type DivideByZeroException.
There is no way for CLR to know that you want to throw other exception.
But if you want to play with your new exception, you can do it like this:
public double Divide(int a, int b)
{
if(b == 0) throw new zeroMessage();
return a /b;
}
and use it:
try
{
var result = Divide(10, 0);
}catch(zeroMessage exc)
{
//here you will catch your exception.
}
However there is no sense in such exception, except education goals.
Judging by your code alone, nowhere do you actually throw zeroMessage.
If you want to intercept DivideByZeroException then that is what you have to do.
Get rid of the zeroMessage type, since it has no bearing on the results here, and change the catch code to this:
catch (DivideByZeroException e)
{
...
Note that the code in the runtime will throw exceptions known to the runtime at the time the runtime was compiled. It will not magically pick up that you want to substitute some exceptions for your own. The only way to catch a "x / 0" problem in your code is to catch the DivideByZeroException, not by inventing your own exception type.
Both DivideByZeroException and your zeroMessage class derive from System.Exception. However that doesn´t mean that DivideByZeroException derives from zeroMessage!
What are you trying to achieve? Use System.Exception if you want to catch all possible exceptions, and use DivideByZeroException and the likes, when you are interested in a particular exception like:
double z; int i = 0;
try
{
z = 10 / i;
Console.WriteLine("N={0} i={1} Result={2}", 10, i, z);
}
catch (DivideByZeroException e)
{
Console.WriteLine("N={0} i={1} Result={2}", 10, i, e.Message);
}
catch(Exception e)
{
Console.WriteLine("Unexpected error: ", e.Message);
}

Categories

Resources