Handling Casting exceptions in a foreach statement - c#

Ok, lets say I have an array of objects in C# .Net like so:
object[] myObjects = new object[9];
myObjects[0] = "Foo";
myObjects[1] = 3;
myObjects[2] = 2.75;
myObjects[3] = "Bar";
myObjects[4] = 675;
myObjects[5] = "FooBar";
myObjects[6] = 12;
myObjects[7] = 11;
myObjects[8] = "FooBarFooBar";
I want to, inside a foreach block, enumerate this array and write every string to a text document using StreamWriter like so:
StreamWriter sw = new StreamWriter(#"C:\z\foobar.txt");
foreach(string myObject in myObjects)
{
sw.WriteLine(myObject);
}
sw.Flush();
sw.Close();
My problem is that whenever I try to cast the integers and doubles to String, an exception will be thrown.
If I put a try/catch block around my foreach statement, the exception that gets thrown on the second iteration will trigger the catching of the exception and nothing will get written to my text document.
Putting the try/catch inside the foreach is pointless because the exception happens on the cast.
I want to use a foreach loop (let's assume that for loops don't exist, and that we can't use indexing or ToString()) to enumerate an array of objects, casting each to a string and writing these to a text document using StreamWriter. If the cast works, happy days. If not, I want to catch the exception thrown and continue to enumerate the remaining objects.
Thanks
Edit: Before somebody says it, this isn't homework! I am trying to solve a real world problem.

Because you expect a heterogeneous collection, it's better to avoid throwing InvalidCastException in the first place. Read up on "boneheaded exceptions" in Eric Lippert's excellent Vexing exceptions article.
Option 1: Use the LINQ OfType<TResult>() extension method to pick out only elements of a specified type:
// using System.Linq;
foreach(string myObject in myObjects.OfType<string>())
{
sw.WriteLine(myObject);
}
Option 2: Do the type check yourself:
foreach(object myObject in myObjects)
{
string s = myObject as string;
if (s != null)
sw.WriteLine(s);
}
This option is easy to extend to handle multiple types.
UPDATE:
Ok, but what would happen if, in some outlandish scenario, an exception was still thrown on this line. Is there a way to handle the exception and then continue with my enumeration?
Here are the other ways an exception could be thrown on the foreach line, none of which you can sensibly handle:
myObjects.GetEnumerator() throws an exception. In this case, the enumeration can't be started at all.
IEnumerator<string>.MoveNext() throws an exception. In this case, the enumerator is likely to be corrupt, and enumeration cannot continue.
Some other type of fatal exception occurs: OutOfMemoryException, StackOverflowException, etc. In this case, you should just let the process die.

You don't need to cast the object to string yourself. StreamWriter has an overload that takes object and does the casting automatically (MSDN link):
foreach (object myObject in myObjects)
{
sw.WriteLine(myObject);
}

Can't you just catch and continue?
StreamWriter sw = new StreamWriter(#"C:\z\foobar.txt");
foreach(string myObject in myObjects)
{
try
{
sw.WriteLine(myObject);
}
catch (Exception ex)
{
// process exception here
continue;
}
}
sw.Flush();
sw.Close();

OK. I know that the question has been answered. But I thought this is interesting. If you want to really get hold of all the exceptions thrown within a foreach loop you could probably store it as a Generic List of type Exception and later you can throw it as an AggregateException
more info in this blog post and this MSDN link
Here is my implementation corresponding to your scenario (this will capture all exceptions thrown within the foreach loop and still the loop won't break until the object array is fully looped)
try
{
List<Exception> exceptions = null;
foreach (object myObject in myObjects)
{
try
{
string str = (string)myObject;
if (str != null)
{
sw.WriteLine(str);
}
}
catch (Exception ex)
{
if (exceptions == null)
exceptions = new List<Exception>();
exceptions.Add(ex);
}
}
if (exceptions != null)
throw new AggregateException(exceptions);
}
catch(AggregateException ae)
{
//Do whatever you want with the exception or throw it
throw ae;
}

Related

Handling multiple exceptions in a loop

In my code, a method is being called repeatedly within a loop like so:
foreach (var file in files)
{
SomeMethod(file);
}
The method is likely to throw exceptions, but I don't want the code to exit the loop after the first exception.
Furthermore, the code above is being called from a web api controller, so I need a way to pass all the exception information back to the controller, where it will be handled (log exception and return error response to the client).
What I've done so far is catch and store all the exception in a list.
var errors = new List<Exception>();
foreach (var file in files)
{
try
{
SomeMethod(file);
}
catch(Exception ex)
{
errors.Add(ex);
}
}
Considering that rethrowing all the errors in the list is not an option, what is the best approach to return the exception information to the controller?
Use AggregateException.
You can pass the List<Exception> to its constructor and throw that.
At the end of your loop do:
AggregateException aggregateEx = new AggregateException(errors);
throw aggregateEx;
(or return AggregateException)
Based on Habib's suggestion, I've implemented a solution that also handles the case where there is just one exception. This way there are no unnecessarily nested exceptions.
if (errors.Any())
{
if (errors.Count > 1)
{
throw new AggregateException("Multiple errors. See InnerExceptions for more details",errors);
}
else
{
ExceptionDispatchInfo.Capture(errors[0]).Throw();
}
}
Simply rethrowing the single exception by calling throw errors[0]; should be avoided as it wouldn't preserve the stack trace of the original exception.

If an Exception is thrown in a List<T>.ForEach, does the iteration stop?

If I have the following code:
List<MyClass> list = GetList();
list.ForEach(i => i.SomeMethod());
and let's say SomeMethod() throws an exception. Does ForEach continue iterating, or does it just stop right there?
If it does terminate, is there any way to get the rest of the items in the collection to run their methods?
Yes, if an exception is thrown, the loop exits. If you don't want that behaviour, you should put exception handling into your delegate. You could easily create a wrapper method for this:
public static Action<T> SuppressExceptions<T>(Action<T> action)
{
return item =>
{
try
{
action(item);
}
catch (Exception e)
{
// Log it, presumably
}
};
}
To be honest, I would try to avoid this if possible. It's unpleasant to catch all exceptions like that. It also doesn't record the items that failed, or the exceptions etc. You really need to think about your requirements in more detail:
Do you need to collect the failed items?
Do you need to collect the exceptions?
Which exceptions do you want to catch?
It would almost certainly be cleaner to create a separate method which used the normal foreach loop instead, handling errors and collecting errors as it went. Personally I generally prefer using foreach over ForEach - you may wish to read Eric Lippert's thoughts on this too.
It will throw an error. You're also well on your way to reimplementing foreach. How about just:
foreach (var item in list)
{
try
{
// dangerous thing with item
}
catch (Exception e)
{
// how do you want to log this?
}
}
This has the benefit of working in most versions of .NET and being obviously side-effectful. Of course, you can put this code directly in the ForEach delegate, but I would only suggest that if it's going to be a method itself (rather than a lambda function).
A reasonable alternative is to create your own ForEachWithCatch extension that captures all the exceptions and sends them back to the caller:
public static IEnumerable<Tuple<T,Exception>> ForEachWithCatch<T>(this IEnumerable<T> items, Action<T> action)
{
var exceptions = new List<Tuple<T,Exception>>();
foreach(var item in items)
{
try
{
action(item);
}
catch(Exception e)
{
exceptions.Add(Tuple.Create(item, e));
}
}
return exceptions;
}
This sends back an enumerable of each item that failed and it's corresponding exception.
If your SomeMethod has implemented try-catch block then foreach will continue
void SomeMethod()
{
try
{
//Some operation on i
}
catch(Exception ex)
{
}
}
But if not then foreach will break.
One what of doing it is this way
list.ForEach(i =>
{
try
{
i.SomeMethod();
}
catch(Exception ex)
{
}
});
But its always good to have zero try-catch blocks in your code. Else you will never find where the culprit is.

Am not sure how to handle the default in switch?

class Program
{
static void Main(string[] args)
{
var getfiles = new fileshare.Program();
string realname = "*test*";
string Location = "SVR01";
foreach (var file in getfiles.GetFileList(realname,Location))
{getfiles.copytolocal(file.FullName); }
}
private FileInfo[] GetFileList(string pattern,string Location)
{
try
{
switch (Location)
{
case "SVR01":
{
var di = new DirectoryInfo(#"\\SVR01\Dev");
return di.GetFiles(pattern);
}
case "SVR02":
{
var di = new DirectoryInfo(#"\\SVR02\Dev");
return di.GetFiles(pattern);
}
case "SVR03":
{
var di = new DirectoryInfo(#"\\SVR03\Prod");
return di.GetFiles(pattern);
}
default: throw new ArgumentOutOfRangeException();
}
}
catch(Exception ex)
{ Console.Write(ex.ToString());
return null;
}
}
private void copytolocal(string filename)
{
string nameonly = Path.GetFileName(filename);
File.Copy(filename,Path.Combine(#"c:\",nameonly),true);
}
}
Am handle the default switch statement but not sure am doing right,some one please correct me .
Thanks in Advance
You should throw an exception only in cases where you don't expect something to happen. If a directory other than SRV01/02/03 is not expected, throwing exception could be fine. If you expect it to happen and want to handle it gracefully, don't throw an exception.
But catching the exception you just threw and writing it to the console in the same function doesn't make sense. You kill all the purpose of throwing an exception there. If you want to write an error to the console, you can do that directly in the default statement.
If you want to handle the case when GetFiles throws an exception, handle it specifically. Catching an exception and writing it to console does not make sense. If you catch it, it means that you know what to do with it. If you don't, don't catch it.
Say your network is dead and GetFiles raises IOException. You catch it and return null and your code will raise NullReferenceException. Because of that, you lose the information about why that exception is raised.
What do you want to do if network connection is lost? You want to exit? Then you don't need to do anything, an unhandled exception already does that for you. You need to continue running? Are you sure? If app exits successfully will it mean "it has completed everything it's supposed to do" or "there could have been problems but you don't care"? If you're sure it's ok to "ignore" the error, then catch the exception, inform and continue, it's fine. Just make sure of your intent. Exceptions aren't bad or evil. They are there because they are helpful.
I see that you simply need to check if a location is in a list of allowed locations. I don't think a switch is a good candidate for something like this. It looks more like configuration, maybe something along the following lines would allow you to read such values from a configuration file for example. Also the logic in each switch statement is the same, so if we can minimise this repetition, it's a bonus
private List<string> _allowedLocations
public YourClassConstructor()
{
_allowedLocations = new List()
{#"\\SVR01\Dev", #"\\SVR02\Dev", #"\\SVR02\Dev"}
}
private FileInfo[] GetFileList(string pattern,string location)
{
if (location == null)
throw new ArgumentNullException("location");
if (!_allowedLocations.Contains(location))
throw new ArgumentOutOfRangeException("location");
var di = new DirectoryInfo(location);
return di.GetFiles(pattern);
}
The default in a switch statement is basically a catch all (or what youre doing in your catch statement). If something lands in your switch statement and hits the default, it may as well gone to your catch. My suggestion, return a null and write to the console whatever your exception is. If your exception works, keep it as is. Like #SLaks said, you can do whatever you want in your default clause, because it is the switches form of a catch statement.
If it's only for an internal environment where you have full control of the network paths, then you have the option to make an enum for location, which would give you the advantage of each possibility showing up in Intellisense. I additionally agree with what Kevin pointed out, in that you are throwing the exception only to catch it yourself within the same method (an antipattern). The enum is my only suggestion, otherwise your understanding and implementation of default is correct (i.e., to catch all unexpected/invalid cases).

Preserving the type of a re-thrown exception

I am writing a class that does operations to multiple streams. Here is a example of what I am doing now
Dictionary<int, int> dict = new Dictionary<int, int>(_Streams.Count);
for (int i = 0; i < _Streams.Count; i++)
{
try
{
dict.Add(i, _Streams[i].Read(buffer, offset, count));
}
catch (System.IO.IOException e)
{
throw new System.IO.IOException(String.Format("I/O exception occurred in stream {0}", i), e);
}
catch (System.NotSupportedException e)
{
throw new System.NotSupportedException(String.Format("The reading of the stream {0} is not supported", i), e);
}
catch (System.ObjectDisposedException e)
{
throw new System.ObjectDisposedException(String.Format("Stream {0} is Disposed", i), e);
}
}
int? last = null;
foreach (var i in dict)
{
if (last == null)
last = i.Value;
if (last != i.Value)
throw new ReadStreamsDiffrentExecption(dict);
last = i.Value;
}
return (int)last;
I would like to simplify my code down to
Dictionary<int, int> dict = new Dictionary<int, int>(_Streams.Count);
for (int i = 0; i < _Streams.Count; i++)
{
try
{
dict.Add(i, _Streams[i].Read(buffer, offset, count));
}
catch (Exception e)
{
throw new Exception(String.Format("Exception occurred in stream {0}", i), e);
}
}
int? last = null;
foreach (var i in dict)
{
if (last == null)
last = i.Value;
if (last != i.Value)
throw new ReadStreamsDiffrentExecption(dict);
last = i.Value;
}
return (int)last;
However if anyone is trying to catch specific exceptions my wrapper will hide the exception that Read threw. How can I preserve the type of exception, add my extra info, but not need to write a handler for every possible contingency in the try block.
I would suggest not catching those exceptions at all...
The information you add could (mostly) be gleaned from the stackdump.
You could use catch-and-wrap to translate to a library-specific exception:
catch (Exception e)
{
throw new ReadStreamsErrorExecption(
String.Format("Exception occurred in stream {0}", i), e);
}
I think you have a bit of an issue here in the way you are working with your exception.
You should not be throwing the base Exception class, but something more specific so they can handle it.
Is the id value something that is really "valuable" from a diagnostic function?
I would review what you are doing, and see if you really need to be wrapping the exception.
I find the first version is better for readability and is the more expressive to my eye. This is how exception handling should be written.
Generally the rule that I've picked up from Eric Lipperts blogs, is that you should only capture an exception if you're going to do something about it.
Here you are just re-throwing the exception with a new message. Just let the client handle the exceptions themselves unless you're going to try and recover from errors. In which case add a
throw;
If you need to bubble the exception backup because you can't handle it.
One little known .NET trick is that you CAN add information to an Exception without wrapping it. Every exception has a .Data dictionary on it that you can stuff with additional information, e.g.
try
{
...
}
catch (FileNotFoundException ex)
{
ex.Data.Add("filename", filename);
throw;
}
Now in your top-level exception handling code you can dump the exception and its associated dictionary out to your log file or into your Exceptions database and thus get far more information than you had before.
In an ASP.NET application you might want to add the URL, the username, the referrer, the contents of the cookies, ... to the .Data dictionary before letting your application error handler take it.

Unhandled Exception in List Sort

So, I have a list containing a custom class, MyClass
MyClass has properties, which can be null (but aren't meant to be).
When this class is sorted, using a custom sorter, where the sorter accesses this null property and throws an exception, the exception is considered unhandled, even though there is a try-catch block around the sort method.
Now for some reason the exception still gets written to the console, which is what the exception handler is doing.
I have a real application with this same issue, causing my unit tests to fail, even though the exception is handled correctly and I cannot explain this.
So I have attached some sample code to explain myself better, run this from VS.
Updated Code
Results:
System.InvalidOperationException
Failed to compare two elements in the array.
Done!
So it seems to be handling my custom exception, and throwing its own?
using System;
using System.Collections.Generic;
using System.Data;
namespace TestSortException
{
class Program
{
static void Main()
{
try
{
var list = new List<MyClass>
{
new MyClass("1"),
new MyClass(null),
new MyClass("fdsfsdf")
};
list.Sort(new MyClassSorter());
}
catch(Exception e)
{
Console.WriteLine(e.GetType());
Console.WriteLine(e.Message);
}
Console.WriteLine("Done!");
Console.ReadLine();
}
}
class MyClassSorter : IComparer<MyClass>
{
public int Compare(MyClass x, MyClass y)
{
// try
// {
if (x.MyString == y.MyString)
return 0;
// Unhandled??? Exception here
if (x.MyString.Length > y.MyString.Length)
return 1;
return -1;
// }
// catch (Exception)
// {
// return -1;
// }
}
}
class MyClass
{
private string _myString;
public string MyString
{
get
{
if (_myString == null) throw new DataException("MyString is Null");
return _myString;
}
}
public MyClass(string myString)
{
_myString = myString;
}
}
}
There's a try/catch block round the Sort method, yes - and that catch block catches the exception. In other words, Sort throws an exception and your catch block catches it. It doesn't propagate out beyond Main - so "Done!" is printed.
This is exactly what I'd expect. In what way is it "unhandled" in your experience? Were you expecting Sort not to throw the exception? It needs to do something to indicate the failure to compare two elements, and this seems to be the most appropriate course of action.
In what way are your unit tests failing? Are you deliberately giving them invalid data? How do you want your comparison code to react to invalid data? If it should ignore it (and return a comparison based on another property), then you should actively check the property rather than letting an exception propagate. In most cases I'd rather allow the exception if this indicates that there's a bug earlier on though.
EDIT: Based on your other comments, it sounds like you're doing the appropriate thing, letting the exception bubble up - but it's not clear in what way you're seeing the exception not be handled.
If you're running in the debugger, it may be breaking on the exception being thrown, but that doesn't mean it won't be handled. Try either changing your exception settings or running without the debugger.
EDIT: Yes, Sort will catch the exception and throw an InvalidOperationException instead - but you can use the InnerException property of that exception to get hold of the original one. It's unfortunate that the documentation doesn't specify this :(
For example, when it checks that string "1" isn't equal to null. But it wants then to compare lengths of "1" string and null => which is impossible.
I assume you work with .Net Framework 4.0. The new thing there is that a NullRefenrenceException can not be caught any more (similar to OutOfMemory exception).

Categories

Resources