2012-12-19 28 views
5

Giả sử tôi có phương thức sau đây. Trong một số đã đếnTrả về một phần tử đơn lẻ từ một khối lặp - Iterator không thể chứa câu lệnh return

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); 

      } 

     } 
    } 

Tình hình thực tế phức tạp hơn một chút nhưng tôi đã bỏ rất nhiều mục đích minh họa. Vấn đề là trong một số trường hợp, tôi muốn lặp lại để tiếp tục thu thập nhiều lỗi ... nhưng trong các trường hợp khác có lỗi nghiêm trọng và tôi chỉ muốn trả lại một lỗi nhưng nó sẽ không cho phép tôi:

&hl=vi
Iterator cannot contain return statement 

Tôi nên làm gì?

+2

Tôi cho rằng thông báo lỗi khá rõ ràng. Bạn không thể trộn 'yield' và' return', vì việc thực hiện hàm được hoãn lại cho đến khi trình vòng lặp được gọi. Tôi muốn đề nghị loại bỏ 'yield' và chỉ xây dựng điều tra của riêng bạn. Tôi hy vọng Jon Skeet hoặc Eric Lippert sẽ kêu vang ở đây về chính xác lý do tại sao trình biên dịch không thể xử lý trường hợp này mặc dù. –

Trả lời

10

Nếu bạn chỉ muốn trả về một tập hợp các kích thước, bạn có thể làm điều này:

if(!user.Activated) 
{ 
    yield return new ValidationResult("NotActived", Resources.UserNotActivated); 
    yield break; 
} 
+0

Cảm ơn, đây là giải pháp đơn giản mà tôi cần. – parliament

3

Tuyên bố trả về không thực sự là lợi nhuận?

yield return ValidationResult("NotActived", Resources.UserNotActivated); 

Nếu bạn thực sự cần phải trả lại một bộ sưu tập, bạn có thể yield return một bộ sưu tập, quá (như bạn có nó), nó chỉ là không cần thiết vì bạn chỉ có một.

Ngoài ra, trong trường hợp mà bạn muốn dừng lại liệt kê một cách rõ ràng, bạn có thể sử dụng yield break;

3

Như được biểu thị bằng thông báo lỗi, bạn không thể kết hợp các câu lệnh yield return và các câu lệnh return thành một phương thức.

Bạn có hai cách tiếp cận chung:

  1. Phương pháp này nên được đánh giá háo hức; bạn nên sử dụng tất cả các câu lệnh return, tìm cách chuyển đổi tất cả các câu lệnh yield thành trả về.
  2. Phương pháp nên sử dụng thực thi hoãn lại, tìm cách chuyển tất cả các câu lệnh return thành câu hỏi yield.

Trong trường hợp của bạn, có thể là # 2, nhưng trong các trường hợp khác có thể thích hợp.

Bây giờ, làm thế nào để biến một yield thành một return:

quấn yếu tố duy nhất vào một bộ sưu tập của một số loại và trả lại rằng:

return new[]{ someItemToReturn }; 

hoặc

return Enumerable.Repeat<T>(someItemToReturn, 1); 

Bây giờ, cách để biến một return thành một yield:

foreach(var item in collectionYouWereReturning) 
    yield return item; 

Bạn có thể sử dụng yield break; để cho biết chuỗi đã kết thúc ngay cả khi phương pháp chưa đạt đến kết thúc tự nhiên. Lưu ý rằng yield break; nên khá hiếm khi được sử dụng. Sử dụng nó rất nhiều sẽ là mùi mã (nhưng điều này có vẻ như một trường hợp mà nó sẽ là thích hợp).

Bây giờ, lý tưởng, chúng tôi muốn có một từ khóa yield foreach của một số loại để bạn có thể lấy tập hợp bên trong khối lặp, nhưng chưa có từ khóa nào được thêm vào ngôn ngữ.

+0

Cảm ơn bạn đã phản hồi, tôi đã học được một vài điều hữu ích trong tương lai nhưng trong trường hợp này tôi thích giữ cùng một mẫu mà tôi sử dụng ở mọi nơi (trả lại lợi nhuận) nhưng chỉ trả lại một phần tử trong các trường hợp ngoại lệ. Câu trả lời của Paul Phillips rất đơn giản và hiệu quả. Upvote cho chắc chắn. – parliament