2012-03-06 49 views
45

Các biểu thức lambda (và ở một mức độ, các hàm ẩn danh) có bị đóng không?Biểu thức Lambda trong C# có bị đóng không?

Sự hiểu biết của tôi về đóng cửa là chúng là các hàm được coi là đối tượng, có vẻ như là một biểu diễn chính xác về những hàm ẩn danh và biểu thức Lambda làm.

Và có đúng không khi gọi chúng là đóng cửa? Tôi hiểu rằng việc đóng cửa đến (hoặc trở nên phổ biến) do phương ngữ lisp, nhưng nó cũng là một thuật ngữ chung?

Cảm ơn bạn đã giải thích rõ ràng rằng bạn có thể cung cấp!

+5

NB được gọi là đóng. "Clojure" là một ngôn ngữ (do đó tôi chỉnh sửa). –

+0

Ah - điều đó chắc chắn xóa bỏ sự nhầm lẫn đó! Cảm ơn –

+0

Đóng cửa là một khía cạnh của biểu thức lambda. Lambdas không nhất thiết phải hỗ trợ đóng cửa. Một số ngôn ngữ thực hiện nó một cách khác nhau. Ví dụ, Java là khác nhau từ C# trong đó trước đây không cho phép sửa đổi của đóng trên biến trong chức năng. Điều đó nói rằng tôi nghĩ rằng câu hỏi này là về sự hiểu biết chung, do đó trùng lặp của [Sự khác biệt giữa một 'đóng cửa' và 'lambda' là gì?] (Http://stackoverflow.com/questions/220658/what-is-the- sự khác biệt giữa một-một-đóng-và-một-lambda) – nawfal

Trả lời

91

Một lambda có thể được thực hiện bằng cách sử dụng một đóng cửa, nhưng nó không phải là bản thân nó nhất thiết là một đóng cửa.

A closure là "một hàm cùng với môi trường tham chiếu cho các biến không phải cục bộ của hàm đó".

Khi bạn tạo biểu thức lambda sử dụng các biến được xác định bên ngoài phương thức, thì lambda phải được triển khai bằng cách đóng. Ví dụ:

int i = 42; 

Action lambda =() => { Console.WriteLine(i); }; 

Trong trường hợp này, trình biên dịch tạo ra phương pháp phải có quyền truy cập vào biến (i) định nghĩa trong một phạm vi hoàn toàn khác nhau. Để làm việc này, phương thức nó tạo ra là một "hàm cùng với môi trường tham chiếu" - về cơ bản, nó tạo ra một "đóng cửa" để truy xuất biến đó.

Tuy nhiên, lambda này:

Action lambda2 =() => { Console.WriteLine("Foo"); } 

không dựa trên bất kỳ "môi trường tham khảo", vì nó là một phương pháp chứa đầy đủ. Trong trường hợp này, trình biên dịch tạo ra một phương thức tĩnh bình thường, và không có đóng cửa nào cả.

Trong cả hai trường hợp, lambda đang tạo một delegate ("đối tượng hàm"), nhưng nó chỉ tạo ra đóng trong trường hợp đầu tiên, vì lambda không nhất thiết phải "chụp" môi trường tham chiếu trong mọi trường hợp .

+2

'var lambda2 =() => {Console.WriteLine (" Foo "); } '* Không dựa vào bất kỳ" môi trường tham chiếu "nào, vì nó là một phương thức được chứa đầy đủ. * Nó đóng trên hệ thống IO! :) –

+0

@DanielEarwicker Tôi sẽ không xem xét tham chiếu .NET như đóng trên hệ thống. Thiết lập môi trường hoạt động của bạn trong đó chức năng hoạt động, không tạo ra một môi trường đặc biệt cho chính hàm đó (được truyền với nó). Có một sự khác biệt. –

+1

Nó chỉ là một nhận xét nửa nghiêm trọng - có, không cần trình biên dịch C# để tạo ra một lớp đặc biệt để biểu diễn một sự đóng cửa.Nhưng nói chung, việc đóng cửa là bất kỳ tình huống nào mà một hàm phụ thuộc vào một số giá trị không được truyền vào một tham số chính thức. Theo nghĩa đó, ngay cả một chương trình C đơn giản, với một hàm đề cập đến một biến toàn cầu, là một ví dụ về việc đóng cửa. –

7

Có. Các đóng thường lấy các biến từ phạm vi bên ngoài. Lambdas có thể làm điều đó. Tuy nhiên nếu lambda của bạn không nắm bắt bất cứ điều gì, nó không phải là một đóng cửa.

+0

Bởi định nghĩa này sẽ một lambda không có biến bên ngoài là một đóng cửa? – Yuck

+2

Lambdas * có thể * làm điều đó. Câu trả lời của Jason chính xác hơn. –

+0

Thuật ngữ "đóng cửa" có thể được xác định rõ ràng, nhưng nó được sử dụng một cách lỏng lẻo trong thực tế. Tôi không nghĩ rằng nó có thể chắc chắn nói rằng lambdas mà chụp không có gì không phải là đóng cửa. – usr

11

Đó là "đóng cửa" chứ không phải "clojure".

Đó không phải là việc đóng cửa. Một đóng về cơ bản là một biểu diễn của một hàm cùng với bất kỳ biến không phải cục bộ nào mà hàm đó tiêu thụ.

Trong ý nghĩa đó, lambdas không bị đóng, nhưng chúng gây ra các bao đóng được tạo bởi trình biên dịch nếu chúng đóng trên bất kỳ biến nào.

Nếu bạn sử dụng ILDASM trên một assembly có chứa lambda đóng trên một số biến, bạn sẽ thấy trong assembly đó một trình biên dịch tạo ra lớp đại diện cho hàm và các biến đã đóng. Điều đó việc đóng.

Khi bạn nói

chức năng mà được coi là đối tượng,

đó là bình thường chỉ là "đối tượng chức năng" (trong C# chúng ta muốn nói "đại biểu") và là phổ biến trong lập trình chức năng .

59

Câu trả lời của Reed là chính xác; Tôi sẽ chỉ cần thêm vài chi tiết bổ sung:

  • lambda biểu thứcphương pháp vô danh cả hai đều có ngữ nghĩa đóng cửa; có nghĩa là, họ "nắm bắt" các biến bên ngoài của họ và kéo dài tuổi thọ của các biến đó.

  • chức năng ẩn danh là thuật ngữ chúng tôi sử dụng khi chúng tôi ngụ ý biểu thức lambda hoặc phương thức ẩn danh. Vâng, điều đó thật khó hiểu. Lấy làm tiếc. Đó là điều tốt nhất chúng tôi có thể nghĩ ra.

  • một hàm có thể được coi là đối tượng chỉ là đại biểu. Điều gì làm cho một lambda một đóng cửa là nó nắm bắt các biến bên ngoài của nó.

  • biểu thức lambda được chuyển thành cây biểu thức cũng có ngữ nghĩa đóng cửa, đủ thú vị. Và thực hiện chính xác đó là một cơn đau ở cổ, tôi nói với bạn!

  • "điều này" được coi là "biến bên ngoài" cho mục đích tạo ra một đóng cửa mặc dù "điều này" không phải là một biến.

+1

Trong khi 'này' isn ' t thực sự là một biến, tôi không nghĩ rằng nó quá đáng ngạc nhiên rằng nó sẽ được coi là một cho các mục đích của ngữ nghĩa đóng cửa. Nó hoạt động rất giống với cách biến "chỉ đọc" sẽ hoạt động. Ngoài ra, tôi nghĩ rằng đó là một phần trực quan của bối cảnh mà một đóng cửa được dự định để nắm bắt. Cuối cùng, đó là một ví dụ mà giả định (mặc dù phổ biến, có vẻ như) giả định rằng đóng cửa nắm bắt các giá trị không phải là quá gây tổn hại: 'this' chắc chắn sẽ không thay đổi sau khi thực tế! – dlev

+5

@dlev: không ngạc nhiên về "điều này" trong loại tham chiếu. Trong một kiểu giá trị, đôi khi mọi người tận dụng lợi thế của thực tế rằng "điều này" là hợp lý * một bí danh cho biến chứa giá trị của cấu trúc *; đóng trên "this" khi trong một phương thức của một loại giá trị có thể thay đổi có thể tạo ra kết quả không mong muốn. –