Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

yield return with try catch, how can i solve it

I've a piece of code:

using (StreamReader stream = new StreamReader(file.OpenRead(), Encoding)) {     char[] buffer = new char[chunksize];     while (stream.Peek() >= 0)     {        int readCount = stream.Read(buffer, 0, chunksize);         yield return new string(buffer, 0, readCount);     }  } 

Now i have to surround this with an try-catch block

try {    using (StreamReader stream = new StreamReader(file.OpenRead(), Encoding))    {        char[] buffer = new char[chunksize];        while (stream.Peek() >= 0)        {           int readCount = stream.Read(buffer, 0, chunksize);            yield return new string(buffer, 0, readCount);        }     }  } catch (Exception ex) {     throw ExceptionMapper.Map(ex, file.FullName) } 

I can't see any way to do what i want.

EDIT The method has the signature

public IEnumerable<string> ReadPieces(int pieces) 

I need a try catch with a call to the ExceptionMapper in the catch case. The method is used deferred by all callers.

The exceptions i have to catch are coming from these calls

File.OpenRead() stream.Read() 
like image 591
Khh Avatar asked Feb 21 '11 14:02

Khh


People also ask

Can you return in a Catch statement?

Yes, we can write a return statement of the method in catch and finally block. There is a situation where a method will have a return type and we can return some value at any part of the method based on the conditions.

What does a try catch return?

In a try-catch-finally block that has return statements, only the value from the finally block will be returned. When returning reference types, be aware of any updates being done on them in the finally block that could end up in unwanted results.

What happens after a try catch?

If there is no exception occurred in the code which is present in try block then first, the try block gets executed completely and then control gets transferred to finally block (skipping catch blocks). If a return statement is encountered either in try or catch block. In this case finally block runs.


2 Answers

Here is a code snippet, which works for me (I did not reach the error condition).

while (true) {     T ret = null;     try     {         if (!enumerator.MoveNext())         {             break;         }         ret = enumerator.Current;     }     catch (Exception ex)     {         // handle the exception and end the iteration         // probably you want it to re-throw it         break;     }     // the yield statement is outside the try catch block     yield return ret; } 
like image 76
Thomas Avatar answered Sep 25 '22 05:09

Thomas


Because you want to keep the Stream open for the duration of the enumeration AND deal with exceptions AND properly close the file handle either way, I don't think you can use a regular enumeration shortcut (the iterator block, yield-return/yield-break).

Instead, just do what the compiler would have done for you and add some:

By implementing IEnumerator yourself, you can also add IDisposable

public class LazyStream : IEnumerable<string>, IDisposable {   LazyEnumerator le;    public LazyStream(FileInfo file, Encoding encoding)   {     le = new LazyEnumerator(file, encoding);   }    #region IEnumerable<string> Members   public IEnumerator<string> GetEnumerator()   {     return le;   }   #endregion    #region IEnumerable Members   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()   {     return le;   }   #endregion    #region IDisposable Members   private bool disposed = false;    public void Dispose()   {     Dispose(true);      GC.SuppressFinalize(this);   }    protected virtual void Dispose(bool disposing)   {     if (!this.disposed)     {       if (disposing)       {         if (le != null) le.Dispose();       }        disposed = true;     }   }   #endregion    class LazyEnumerator : IEnumerator<string>, IDisposable   {     StreamReader streamReader;     const int chunksize = 1024;     char[] buffer = new char[chunksize];      string current;      public LazyEnumerator(FileInfo file, Encoding encoding)     {       try       {         streamReader = new StreamReader(file.OpenRead(), encoding);       }       catch       {         // Catch some generator related exception       }     }      #region IEnumerator<string> Members     public string Current     {       get { return current; }     }     #endregion      #region IEnumerator Members     object System.Collections.IEnumerator.Current     {       get { return current; }     }      public bool MoveNext()     {       try       {         if (streamReader.Peek() >= 0)         {           int readCount = streamReader.Read(buffer, 0, chunksize);            current = new string(buffer, 0, readCount);            return true;         }         else         {           return false;         }       }       catch       {         // Trap some iteration error       }     }      public void Reset()     {       throw new NotSupportedException();     }     #endregion      #region IDisposable Members     private bool disposed = false;      public void Dispose()     {       Dispose(true);        GC.SuppressFinalize(this);     }      protected virtual void Dispose(bool disposing)     {       if (!this.disposed)       {         if (disposing)         {           if (streamReader != null) streamReader.Dispose();         }          disposed = true;       }     }     #endregion   } } 

I didn't test this, but I think it's close.

used like this:

using (var fe = new LazyStream(new FileInfo("c:\\data.log"), Encoding.ASCII)) {   foreach (var chunk in fe)   {     Console.WriteLine(chunk);   } } 

EDIT: I had totally forgotten to add the try-catch block placements. Oops.

like image 35
Jason Kleban Avatar answered Sep 23 '22 05:09

Jason Kleban