views:

145

answers:

1

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?

A: 

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

shambulator
Thanks for the reply shambulator. I guess then the answer to the "how can I get around it" part of my question is "you can't without changing your design"?
Stuart
Afraid so, at least as far as I can see.
shambulator