Reputation: 28069
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.
Upvotes: 3
Views: 2891
Reputation: 4361
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;
}
Upvotes: 0
Reputation: 34325
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();
Upvotes: 0
Reputation: 55469
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.OutOfMemoryException
, StackOverflowException
, etc. In this case, you should just let the process die.Upvotes: 6