Search code examples
c#methodstry-catchienumerableyield-return

Try-Catch with Yield return in a Recursive Method


I need to implement a try catch in a recursive method, but i can't figure out how to do it. This is the code:

    private IEnumerable <FileItem> FilesToDownload(FileItem file)
    {
        logger = LogManager.GetLogger(GetType());

        using (var wb = new WebDavSession(webDavUrl, new NetworkCredential(user, psw)))
        using (Task<IList<WebDavSessionItem>> task = wb.ListAsync(file.Path))
        {
            task.Wait();
            foreach (var item in task.Result)
            {
                FileItem retFile = item.ToFileItem();
                logger.Info("Going Into " + retFile.Path);
                if (item.IsFolder == true)  
                {
                    foreach (var inner in FilesToDownload(retFile))
                    {
                        yield return inner;
                    }
                }
                else
                {
                    yield return retFile;
                }
            }
        } 
    }

This method helps me to find out files into nested folders (in a cloud), so the recursive is necessary.

Whay do you suggest?


Solution

  • What you can't do is have a try/catch block around a yield return statement - that violates CS1626.

    But: you can still use try/catch - you just need to be creative in the layout. For example:

    foreach (var item in task.Result)
    {
        IEnumerable<FileItem> subItems = null;
        FileItem subItem = null;
    
        try
        {
            FileItem retFile = item.ToFileItem();
            logger.Info("Going Into " + retFile.Path);
            if (item.IsFolder == true)
            {
                subItems = FilesToDownload(retFile);
            }
            else
            {
                subItem = retFile;
            }
        }
        catch { /* your code here */ }
        if (subItem != null) yield return subItem;
        if (subItems != null)
        {
            foreach (var x in subItems) yield return x;
        }
    }
    

    Additional thoughts:

    • a Stack<T> or Queue<T> may be a more suitable approach than deep recursion
    • the task.Wait() is not good and could deadlock your code; unfortunately there is currently no good pattern for "async enumerables"