2010-10-10 37 views
7

Tôi biết rằng các biểu thức lambda .NET có thể nắm bắt các biến bên ngoài. Tuy nhiên, tôi đã nhìn thấy nó rất nhiều lần các biến được chuyển một cách rõ ràng đến biểu thức lambda như một tham số, và thư viện .NET cũng có vẻ hỗ trợ (ví dụ: ThreadPool.QueueUserWorkItem).Biểu thức Lambda, các biến được chụp và luồng

Câu hỏi của tôi là những hạn chế của những ảnh chụp này là gì? Làm thế nào về lambdas được thực sự thực hiện trên một chủ đề khác nhau hơn là một trong họ đã được tạo ra trên (ví dụ như ThreadPool.QueueUserWorkItem, hoặc Thread), hoặc lambas hoạt động như callbacks (tức là được gọi vào một thời gian sau đó)?

Nói chung, khi nào tôi nên dựa vào các biến bị bắt và khi nào nên sử dụng các thông số rõ ràng? Ví dụ:

public void DoStuff() 
{ 
    string message = GetMessage(); 

    ThreadPool.QueueUserWorkItem(s => SendMessage(message)); // use captured variable 
    // -- OR -- 
    ThreadPool.QueueUserWorkItem(s => 
      { 
       string msg = (string)s; 
       SendMessage(msg); 
      }, message); // use explicit parameter 
} 

Cảm ơn bạn!

Cập nhật: cố định ví dụ ThreadPool.QueueUserWorkItem thứ hai.

Trả lời

9

Tôi nghĩ rằng trong ví dụ đầu tiên của bạn., Bạn có nghĩa là

QueueUserWorkItem(() => SendMessage(message)); 

Trong mục thứ hai của bạn, nơi không tham số s đến từ đâu? Tôi nghĩ rằng bạn có nghĩa là

QueueUserWorkItem(s => {SendMessage((string)s);} , message); 

Bây giờ, hai cả hai làm việc tương đương, nhưng

  • Trong trường hợp thứ nhất: các tham số message được sao chép từ phạm vi phương pháp DoStuff này và lưu trữ trực tiếp trong biểu thức lambda của bạn chính nó, như là một đóng cửa. Số lambda có giữ một bản sao của message.

  • Trong trường hợp thứ hai: message được gửi đến Queue, và hàng đợi giữ tổ chức của nó (cùng với lambda), cho đến khi lambda được gọi. Nó là được truyền vào thời điểm chạy lambda, đến lambda.

tôi cho rằng trường hợp thứ hai là lập trình linh hoạt hơn, vì nó về mặt lý thuyết có thể cho phép bạn để sau đó thay đổi giá trị của tham số message trước lambda được gọi. Tuy nhiên, phương pháp đầu tiên dễ đọc hơn và miễn dịch hơn với các tác dụng phụ. Nhưng trong thực tế, cả hai đều hoạt động.

+0

Bạn nói đúng, tôi đã bỏ lỡ thông số trong phần thứ hai của ví dụ. Vì vậy, như tôi hiểu, trong thực tế nó không thực sự quan trọng mà tôi sử dụng, nhưng bạn muốn giới thiệu tôi với đi với các biến bị bắt, vì đơn giản (và dễ đọc). Cảm ơn bạn rất nhiều vì câu trả lời chi tiết của bạn! – ShdNx

5

Ví dụ của bạn (tham chiếu đến đối tượng chuỗi không thay đổi), nó hoàn toàn không có sự khác biệt.

Và nói chung, việc sao chép tài liệu tham khảo sẽ không tạo ra nhiều khác biệt. Việc làm việc với các loại giá trị quan trọng:

double value = 0.1; 

ThreadPool.QueueUserWorkItem(() => value = Process(value)); // use captured variable 

// -- OR -- 

ThreadPool.QueueUserWorkItem(() => 
     { 
      double val = value;  // use explicit parameter 
      val = Process(val);  // value is not changed 
     }); 

// -- OR -- 

ThreadPool.QueueUserWorkItem((v) => 
     { 
      double val = (double)v; // explicit var for casting 
      val = Process(val);  // value is not changed 
     }, value); 

Phiên bản đầu tiên không an toàn, thứ hai và thứ ba có thể là.

Phiên bản cuối cùng sử dụng thông số object state là tính năng Fx2 (trước LINQ).

+0

Tôi phải thừa nhận rằng tôi thấy mã ví dụ của bạn khó hiểu. Trong phần đầu tiên, bạn đang sử dụng tham số, nhưng bạn không vượt qua nó để làm lambda. Nhưng sau đó không sử dụng một biến bị bắt (theo hiểu biết của tôi), bởi vì điều đó có nghĩa là trực tiếp sử dụng biến giá trị. Ví dụ thứ hai của bạn chỉ ra cách thức hoạt động của các loại bất biến, điều đó hoàn toàn đúng, nhưng nó không giúp tôi hiểu sự khác biệt. Bạn có thể vui lòng cập nhật câu trả lời của bạn để làm rõ điều này? – ShdNx

+0

@Shnx, bạn nói đúng, viết tồi tàn. Tôi sẽ sửa chữa nó. –

+0

Cảm ơn bạn, rõ ràng là bây giờ. điều duy nhất là bạn cũng nên cập nhật các bình luận trong mã. +1 để đề cập đến an toàn chủ đề (mặc dù nó chỉ hoạt động với các loại bất biến), nhưng tôi chấp nhận câu trả lời của Sanjay Manohar, bởi vì nó nhanh hơn, rõ ràng và chi tiết hơn. Cảm ơn bạn vì sự giúp đỡ của bạn! – ShdNx

1
  1. Nếu bạn muốn các thư viện ẩn danh tham chiếu cùng một tiểu bang, hãy nắm bắt số nhận dạng từ ngữ cảnh chung.
  2. Nếu bạn muốn lambdas không quốc tịch (như tôi muốn giới thiệu trong một ứng dụng đồng thời) sử dụng bản sao cục bộ.
Các vấn đề liên quan