Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with debug watch in Visual Studio with yield return enumerator methods

I have a method which returns an IEnumerable<> which it builds up using the yield return syntax:

namespace Validation
{
    public class UserValidator
    {
        public IEnumerable<ValidationError> Validate(User user)
        {
            if (String.IsNullOrEmpty(user.Name))
            {
                yield return new ValidationError("Name", ValidationErrorType.Required);
            }

            [...]

            yield break;
        }
    }
}

If I put a breakpoint in the method, I can step over each line, but if I try to use the Watch or Immediate windows to view the value of a variable I get this error:

Cannot access a non-static member of outer type 'Validation.UserValidator.Validate' via nested type 'Validation.UserValidator'

Does anyone know why this is and how I can get around it?

like image 325
stusherwin Avatar asked May 28 '10 08:05

stusherwin


3 Answers

OK, just tried it out and I see what you mean. That's painful! I suspect it has to do with the behind-the-scenes work the compiler does (creating nested classes and such) to implement the resumable state machine-type logic for yield. One way of getting around it (the way I originally tried your code) is to make the Validate method static, though obviously that's not great for the design.

I think the reason the error message is so obtuse is some combination of:

  1. The generated classes don't exist in your source, so VS has no names by which to refer to them.
  2. IIRC, the names generated by the compiler contain characters illegal in C# identifiers, but valid in the underlying Framework type system.

I don't have Reflector handy right now, so can't confirm, but if you're feeling like a spot of light masochism, reflect on your assembly and take a look at the code the compiler writes to let us mere mortals use nice syntactic sugar like yield return :) There's lots of information available on the web on how exactly it all works.

Edit: after a little more searching, a couple of the better ones:
http://blogs.msdn.com/b/ericlippert/archive/tags/iterators/
http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx

like image 119
anton.burger Avatar answered Oct 06 '22 23:10

anton.burger


The method isn't run until you enumerate into it.

var p = UserValidator.Validate(user).ToList();

You can now debug your code.

like image 29
keshav Avatar answered Oct 07 '22 00:10

keshav


I've had similar problems, and what I have done is to modify the implementation to build up a list of elements, and then return the list.

That has allowed me to find the bug, correct it. After the bug has been corrected, I change the implementation back to a yield return.

Painful.

like image 39
Pete Avatar answered Oct 06 '22 22:10

Pete