Sử dụng biểu thức lambda cho trình xử lý sự kiện


114

Tôi hiện có một trang được khai báo như sau:

public partial class MyPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //snip
        MyButton.Click += (o, i) =>
        {
            //snip
        }
    }
}

Tôi chỉ mới chuyển sang .NET 3.5 từ 1.1, vì vậy tôi đã quen với việc viết các trình xử lý sự kiện bên ngoài Page_Load. Câu hỏi của tôi là; có bất kỳ hạn chế hoặc cạm bẫy nào về hiệu suất mà tôi nên chú ý khi sử dụng phương pháp lambda cho việc này không? Tôi thích nó hơn, vì nó chắc chắn ngắn gọn hơn, nhưng tôi không muốn hy sinh hiệu suất để sử dụng nó. Cảm ơn.

Câu trả lời:


117

Không có hàm ý về hiệu suất vì trình biên dịch sẽ dịch biểu thức lambda của bạn thành một đại biểu tương đương. Biểu thức Lambda không gì khác hơn là một tính năng ngôn ngữ mà trình biên dịch dịch sang cùng một mã chính xác mà bạn đã quen làm việc.

Trình biên dịch sẽ chuyển đổi mã bạn có thành một thứ như thế này:

public partial class MyPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //snip
        MyButton.Click += new EventHandler(delegate (Object o, EventArgs a) 
        {
            //snip
        });
    }
}

Tôi hiểu rồi. Vì vậy, cũng không có hạn chế nào khi có những trình xử lý này bên trong Page_Load so với việc có chúng bên ngoài nó?
Christopher Garcia

1
Quy ước phổ biến là đính kèm các trình xử lý sự kiện trong OnInitphương thức nhưng vì Clicksự kiện của nút sẽ được nâng lên sau khi tải trang, ví dụ này là tốt.
Andrew Hare

8
Điều quan trọng cần lưu ý là nếu không giữ lại tham chiếu tới người được ủy quyền, bạn không thể hủy đăng ký sự kiện.
snarf

3
"cùng một mã" là một chút sai lầm; ít nhất là khi tham chiếu đến các biến cục bộ từ phương thức bao, các biểu thức lambda không được dịch thành các phương thức một cái gì đó giống như một đối tượng bao đóng lưu trữ các giá trị hiện tại của các biến cục bộ.
HOẶC Người lập bản đồ

66

Về mặt hiệu suất, nó cũng giống như một phương pháp được đặt tên. Vấn đề lớn là khi bạn làm như sau:

MyButton.Click -= (o, i) => 
{ 
    //snip 
} 

Nó có thể sẽ cố gắng xóa một lambda khác, để lại lambda ban đầu ở đó. Vì vậy, bài học là không sao cả trừ khi bạn cũng muốn loại bỏ trình xử lý.


3
"Nó có thể sẽ cố gắng để ..."? Nó sẽ bao giờ loại bỏ trình xử lý chính xác trong tình huống như vậy?
HOẶC Người lập bản đồ

1
@ORMapper: Nếu lambda bắt một biến, nó không thể xóa trình xử lý chính xác. Trong các trường hợp khác, nó phụ thuộc vào trình biên dịch.
Gabe

Có thật không? Thật thú vị - vì vậy, nếu tôi đăng ký hai hàm ẩn danh trông giống nhau (wlog có nội dung trống) và sau đó tôi hủy đăng ký (sử dụng -=) một hàm ẩn danh khác cũng có nội dung trống, thì về cơ bản không xác định được hàm nào trong hai trình xử lý sự kiện sẽ bị loại bỏ, hoặc liệu bất kỳ cái nào trong số chúng sẽ bị loại bỏ?
HOẶC Người lập bản đồ

4
@ORMapper: Có. Trình biên dịch được phép (nhưng không bắt buộc) tạo các đại biểu bằng nhau nếu chúng có ngữ nghĩa giống nhau (mã không nhất thiết phải giống nhau, nhưng chúng phải làm điều tương tự) và nắm bắt các trường hợp biến giống nhau (không chỉ các biến giống nhau, nhưng các trường hợp giống nhau của các biến đó). Xem phần 7.10.8 (Ủy quyền toán tử bình đẳng) của thông số kỹ thuật C # để biết tất cả các chi tiết.
Gabe

12
Nếu bạn thực sự muốn sử dụng lambda nhưng cần phải loại bỏ sự kiện này, bạn luôn có thể giữ cho tổ chức của các đối tượng trong một biến / lĩnh vực địa phương sau đó loại bỏ đó, ví dụvar event = (o, e) => doSomething(); handler += event; doSomethingElse(); handler -= event;
Wai Hà Lee

44
EventHandler handler = (s, e) => MessageBox.Show("Woho");

button.Click += handler;
button.Click -= handler;

1
Thông tin rất hữu ích, mặc dù nó lạc đề (câu hỏi là về hiệu suất).
Stéphane Gourichon

4
Không hẳn là lạc đề vì việc sử dụng bộ nhớ có thể dẫn đến hạ cấp hiệu suất.
Vladius

3
Loại bỏ nó trong một handler bản thân cũng có thể hữu ích:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Vladius

2

Không có hàm ý hiệu suất nào mà tôi biết hoặc đã từng gặp phải, theo như tôi biết chỉ là "đường cú pháp" và biên dịch giống như sử dụng cú pháp đại biểu, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.