Returning a single element from an iterator block - Iterator cannot contain return statement

懵懂的女人 提交于 2019-12-10 14:22:32

问题


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:

  1. The method should be eagerly evaluated; you should use all return statements, find a way to convert all yield statements into returns.
  2. The method should use deferred execution, find a way to turn all return statements into yield statements.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!