2015-06-18 27 views
5

Ai đó có thể giải thích cho tôi tại sao truy vấn LINQ sau đây ném một InvalidOperationException?
(Đừng nói rằng danh sách này không có các yếu tố, giá trị mà tôi đang tìm kiếm luôn luôn tồn tại trong bộ sưu tập)Trình tự không chứa các phần tử

class Program 
{ 
    static int lastNumber; 
    static void Main() 
    { 
      int loopCount = 100; int minValue = 1; int maxValue = 10000; 
      var numbers = Enumerable.Range(minValue, maxValue).ToList();//or ToArray(); 
      Random random = new Random(); 

      for (int i = 0; i < loopCount; i++) 
      { 
       //.First() throws the exception but it is obvious that the value exists in the list 
       int x = numbers.Where(v => v == NewMethod(minValue, maxValue, random)).First(); 
      } 
      Console.WriteLine("Finished"); 
      Console.ReadLine(); 

    } 

    private static int NewMethod(int minValue, int maxValue, Random random) 
    { 
     var a1 = random.Next(minValue + 1, maxValue - 1); 
     lastNumber = a1; 
     return a1; 
    } 
} 

Vấn đề chỉ xuất hiện khi tôi gọi NewMethod bên expession lambda tôi.
Nếu làm được điều này nó hoạt động

int temp=NewMethod(minValue, maxValue, random); 
int x = numbers.Where(v => v == temp).First(); 

tôi thêm lĩnh vực lastNumber để giúp gỡ lỗi mã, bạn có thể thấy rằng giá trị tồn tại trong bộ sưu tập khi nó bị treo

PS
Vấn đề không phải là biến ngẫu nhiên, tôi loại bỏ các tham số và tạo ra một mới địa phương ngẫu nhiên trong phương pháp này nhưng vấn đề vẫn còn tồn tại

cập nhật

hóa ra rằng bạn không cần vòng lặp để làm cho nó sụp đổ. Nếu bạn chạy chương trình nhiều lần, bạn sẽ nhận được lỗi một lần nữa

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
class Program 
{ 
    static int lastNumber; 
    static void Main() 
    { 
     int minValue = 1, maxValue = 100000; 
     var numbers = Enumerable.Range(minValue, maxValue).ToArray(); 
     //Crashes sometimes 
     int x = numbers.Where(v => v == NewMethod(minValue, maxValue)).First(); 
     Console.WriteLine("Finished"); 
     Console.ReadLine(); 
    } 

    private static int NewMethod(int minValue, int maxValue) 
    { 
      Random random = new Random(); 
      var a1 = random.Next(minValue + 1, maxValue - 1); 
      lastNumber = a1; 
      return a1; 
     } 
} 
+0

Theo tôi biết bạn không thể sử dụng một phương thức "phức tạp" bên trong biểu thức lamda, chỉ những thứ có thể được chuyển đổi thành câu lệnh. http://stackoverflow.com/questions/1883920/call-a-function-for-each-value-in-a-generic-c-sharp-collection –

+1

@ZivWeissman Bạn có thể gọi các phương thức "phức tạp" - câu hỏi đó là nói về phương pháp _with tác dụng phụ_. –

Trả lời

5

@Oleg là đúng, nhưng đây là lý do tại sao đó là vấn đề.

Where quét qua danh sách tìm kiếm các yếu tố phù hợp với tiêu chí đã cho. Trong trường hợp này, , thay đổi tiêu chí cho mỗi thành phần. Nếu bạn đã thực hiện các vấn đề nhỏ hơn, nói một mảng của 5 yếu tố:

List<Int32> (5 items) 
1 
2 
3 
4 
5 

Và sau đó looped thông qua tìm kiếm một giá trị phù hợp với một số số ngẫu nhiên (x là Item[i]r là một số ngẫu nhiên):

Item 1: x = 1, r = 2 // fail 
Item 2: x = 2, r = 3 // fail 
Item 3: x = 3, r = 2 // fail 
Item 4: x = 4, r = 3 // fail 
Item 5: x = 5, r = 2 // fail 

Lưu ý rằng không có mục nào khớp với số ngẫu nhiên cụ thể đó, vì vậy không có mục nào khớp với tiêu chí và First ném ngoại lệ!

Việc sửa chữa, như bạn đã phát hiện ra, là để tạo ra các số ngẫu nhiên trước kiểu liệt kê:

int temp=NewMethod(minValue, maxValue, random); // say 2 

Item 1: x = 1, temp = 2 // fail 
Item 2: x = 2, temp = 2 // success! 

Side lưu ý:

Đó là một chút sai lầm khi sử dụng maxValue đây:

Enumerable.Range(minValue, maxValue) 

Do tham số thứ hai là Enumerable.Range là chiều dài của tập hợp kết quả, không phải giá trị lớn nhất.Trong trường hợp này, nó hoạt động vì bạn bắt đầu từ 1 nhưng kết quả sẽ là bất ngờ nếu bạn sử dụng, hãy nói 99 và 100 - bạn sẽ có phạm vi từ 99 đến 198.

+0

Tôi không thể tin rằng mình thật ngu ngốc !!! Tôi nghĩ tôi phải đi ngủ !!! –

+0

@GeorgeVovos Đừng cảm thấy xấu - tôi phải tự mô phỏng nó để xem vấn đề! –

4

Đó là vì NewMethod gọi trên mỗi iteration và mỗi lần tạo ra số ngẫu nhiên mới.

Nhưng trong mã này lúc đầu tạo số và sau đó so sánh với từng yếu tố thu thập số.

int temp=NewMethod(minValue, maxValue, random); 
int x = numbers.Where(v => v == temp).First(); 
+1

Không chắc chắn tôi hiểu, số mới tạo ra luôn luôn tồn tại trong bộ sưu tập. Tại sao nó sụp đổ? –

+0

Đúng là số tồn tại trong toàn bộ bộ sưu tập, nhưng con số này không bằng số hiện tại mà trên đó bình đẳng kiểm tra. – Oleg

+0

ooo, tôi hiểu ý của bạn là gì, NewMethod được gọi bên trong nhiều lần, khi bạn nói lặp lại tôi nghĩ vòng lặp –

Các vấn đề liên quan