问题
Let's say I have the following method. In some came
public IEnumerable<ValidationResult> Validate(UserLoginCommand command)
{
User user = userRepository.Get(u => u.Email == command.UserEmail);
if(user != null)
{
if(!user.Activated)
{
return new IEnumerable<ValidationResult>() {new ValidationResult("NotActived", Resources.UserNotActivated)};
}
if(user.IsPasswordIncorrent)
{
yield return new ValidationResult("IncorrectPassword", Resources.IncorrentPassword);
}
}
}
The actual situation is actually a bit more complex but I've left a lot out for illustration purposes.
The point is in some cases, I want to iterator to continue collecting multiple errors...but in other cases there is a fatal error and I only want to return a single error but it will not let me:
Iterator cannot contain return statement
What should I do?
回答1:
If you just want to return a collection of size one, you can do this:
if(!user.Activated)
{
yield return new ValidationResult("NotActived", Resources.UserNotActivated);
yield break;
}
回答2:
Shouldn't that return statement actually be a yield?
yield return ValidationResult("NotActived", Resources.UserNotActivated);
If you really need to return a collection, you can yield return a collection, too (like you have it), it's just not necessary since you have only one.
Also, in the case that you want to stop enumerating explicitly, you can use yield break;
回答3:
As indicated by the error message, you can't mix yield return statements and return statements into a single method.
You have two general approaches:
- The method should be eagerly evaluated; you should use all
returnstatements, find a way to convert allyieldstatements into returns. - The method should use deferred execution, find a way to turn all
returnstatements intoyieldstatements.
In your case, it's probably #2, but in other situations either may be appropriate.
Now, how to turn a yield into a return:
wrap the single element into a collection of some sort and return that:
return new[]{ someItemToReturn };
or
return Enumerable.Repeat<T>(someItemToReturn, 1);
Now, how to turn a return into a yield:
foreach(var item in collectionYouWereReturning)
yield return item;
You can use yield break; to indicate that the sequence has ended even if the method has not reached it's natural end. Note that yield break; should be pretty rarely used. Using it a lot would be code smell (but this does seem like a case where it would be appropriate).
Now, ideally, we'd have a yield foreach keyword of some sort so that you could yield a collection inside of an iterator block, but as of yet no such keyword has been added to the language.
来源:https://stackoverflow.com/questions/13961890/returning-a-single-element-from-an-iterator-block-iterator-cannot-contain-retu