2010-05-13 22 views
5

Tôi có một dự án XNA 3.0 được biên dịch tốt trong VS2008, nhưng cho phép biên dịch các lỗi trong VS2010 (với XNA 4.0 CTP). Lỗi:"Không thể sử dụng biểu thức lambda cục bộ cố định"

Cannot use fixed local 'depthPtr' inside an anonymous method, lambda expression, or query expression

depthPtr là một fixed float* vào một mảng, được sử dụng trong một biểu thức lambda Parallel.For từ System.Threading. Như tôi đã nói, điều này biên dịch và chạy tốt trên VS2008, nhưng nó không trên VS2010, ngay cả khi nhắm mục tiêu .NET 3.5.

Điều này đã thay đổi trong .NET 4.0, và thậm chí như vậy, không nên nó vẫn biên dịch khi tôi chọn .NET 3.5 làm khung mục tiêu? Tìm kiếm cụm từ "Không thể sử dụng cố định địa phương" sản lượng chính xác một (vô dụng) kết quả, cả trong Google và Bing.

Nếu điều này đã thay đổi, lý do cho điều này là gì? Tôi có thể tưởng tượng bắt một loại con trỏ fixed trong một đóng cửa có thể có được một chút lạ, đó là lý do tại sao? Vì vậy, tôi đoán đây là thực hành xấu? Và trước khi bất cứ ai hỏi: không, việc sử dụng con trỏ không hoàn toàn quan trọng ở đây. Tôi vẫn muốn biết mặc dù :)

EDIT: Theo yêu cầu, mẫu mã (không phải từ chương trình của tôi, rõ ràng) nhằm tái tạo lỗi:

static unsafe void Main(string[] args) 
{ 
    float[] array = new float[10]; 

    fixed (float* ptr = array) 
    { 
    Parallel.For(0, 10, i => 
    { 
     ptr[i] = i; 
    }); 
    } 
} 

Các biên dịch nêu trên trong VS2008 (tốt, ngoài tham chiếu đến Parallel, nhưng bất kỳ biểu thức lambda nào khác sẽ làm), nhưng không có trong VS2010.

+1

bạn có thể vui lòng đăng mã gây ra lỗi không. – luke

+0

Vâng, không có nhiều để đăng bài, đó là chính xác những gì lỗi nói: việc sử dụng một con trỏ bên trong một biểu thức lamdba. – JulianR

+0

Tuy nhiên, việc đăng một đoạn mã ngắn nhưng đầy đủ mà chúng tôi có thể thử nghiệm sẽ là một điều tốt (tm). –

Trả lời

3

cố định ghim một con trỏ trong khoảng thời gian của khối. Nếu bạn đã lưu trữ các đại biểu để gọi sau này sau khi khối đã được thoát khỏi bộ thu rác có thể di chuyển đối tượng giữa khi lambda được tạo ra và khi lambda được gọi. Về lý do tại sao nhắm mục tiêu một khung công tác khác không giúp ích, điều này là do điều này đang được thực thi bởi ngôn ngữ/trình biên dịch, không phải thời gian chạy (nếu là thời gian chạy, nó sẽ được báo cáo qua một ngoại lệ hoặc tương tự trong thời gian chạy, chứ không phải bởi trình biên dịch tại thời gian biên dịch).

+0

Ah, do đó, nó chỉ thiết lập phiên bản thời gian chạy và không sử dụng một trình biên dịch cũ hơn? Có ý nghĩa. Về việc ghim mặc dù, có đó là một rủi ro, nhưng tôi có thể dễ dàng khai báo một trường thể hiện trên kiểu còn sống lâu hơn khối cố định, làm cho nó trỏ đến một vị trí không hợp lệ. Tuy nhiên, điều đó vẫn có thể. – JulianR

+0

Tôi không nghĩ rằng nó sẽ có thể kiểm tra tĩnh tất cả các kịch bản một con trỏ được ghim có thể trở thành không hợp lệ, cuối cùng ai đó luôn có thể sử dụng GCHandle. Kiểm tra này có thể chỉ đơn giản là đại diện cho một "nỗ lực tốt nhất" để tránh những vấn đề không rõ ràng có thể xảy ra từ mã như thế này. –

0

Một giải thích có thể là, giá trị của một biến được thực hiện khi thực hiện đóng, chứ không phải định nghĩa. Trong ví dụ của bạn, nó có thể sẽ không gây hại gì, nhưng trong những trường hợp khác, nó có thể xảy ra. Vì vậy, để dạy thực hành tốt, nó bị cấm hoàn toàn để ngăn chặn tất cả các loại lỗi thú vị.

1

doco nói rằng bạn không được phép truy cập mã không an toàn bằng các phương pháp ẩn danh và các hạn chế tương tự áp dụng cho lambdas, vì vậy tôi nghĩ rằng đó có thể là vấn đề của bạn. Bạn có lỗi trình biên dịch thực sự không?

1

Tác phẩm này. Về cơ bản chúng tôi loại bỏ lambda có chứa một con trỏ không an toàn và thay thế nó bằng một đại biểu đến một thể hiện của một lớp được khai báo bên trong khối fixed.

static unsafe void UnsafeTest(string[] args) { 
     float[] array = new float[10]; 

     fixed(float* ptr = array) { 
      UnsafeOps ops = new UnsafeOps(); 
      ops.p = ptr; 

      Parallel.For(0, 10, ops.Lambda); 
     } 
    } 

    unsafe class UnsafeOps { 
     public float* p; 
     public unsafe void Lambda(int value) { 
      p[value] = value; 
     } 
    } 

Dường như với tôi như .NET 4 đã thêm một số nỗ lực nửa khi không cho phép truy cập bộ nhớ cố định trong trình biên dịch. Trong khối mã ở trên, bạn có thể xác định UnsafeOps bên ngoài khối fixed và truy cập mảng sau khối fixed. Vì vậy, nó không hoàn hảo ...

1

Trình biên dịch là chính xác để từ chối mã đó. Cố định chỉ có thể được sử dụng trên các biến cục bộ, và các biến được capture bởi một đóng không phải là các biến cục bộ, chúng được hoisted vào lớp được sử dụng để duy trì trạng thái cho việc đóng.

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