Trang chủ > Uncategorized > Event trong C#

Event trong C#

Tháng Mười 4, 2010 Để lại bình luận Go to comments

Khai báo

Dưới đây là các bước tạo một event. Xem thêm chi tiết ở đây.

public class CustomEventArgs: EventArgs {…} 
public delegate void CustomEventHandler(object sender, CustomEventArgs a); 
public event CustomEventHandler RaiseCustomEvent;

Nếu bạn dùng Generics, bạn không cần phải tự tạo delegate:

public class CustomEventArgs: EventArgs {…} 
public event EventHandler<CustomEventArgs> RaiseCustomEvent;

Nếu bạn không cần một class EventArgs riêng, bạn không phải tạo CustomEventArgs:

public event EventHandler<EventArgs> RaiseCustomEvent;

Raise event

Cần chú ý là bạn nên tách phần code để raise event ra khỏi phần code kiểm tra điều kiện và tạo EventArgs, vì bạn sẽ thấy tiếp theo đây, raise event đòi hỏi một số thao tác linh tinh có thể làm code của bạn rối rắm hơn:

void OnRaiseCustomEvent(CustomEventArgs e) { 
  if (RaiseCustomEvent != null) { 
    RaiseCustomEvent(this, e); 
  } 
}

Tại sao phải kiểm tra null? Vì nếu RaiseCustomEvent là null, tức là chưa có ai subscribe, lệnh raise event sẽ throw Exception.

Vẫn còn một vấn đề nữa. Trong một chương trình multithread, rất có khả năng một object nào đó sẽ hủy subscribe trước khi raise event, nhưng sau khi phép kiểm tra null xảy ra. Nếu việc hủy subscribe này làm cho event thành null, bạn hiểu điều gì sẽ xảy ra. Do đó, bạn phải tạo một bản copy cho event cần raise:

var handler = RaiseCustomEvent; 
if (handler != null) …

Bây giờ thì dù RaiseCustomEvent có thay đổi thế nào, handler event cũng không bị ảnh hưởng. Tại sao một phép copy lại làm được điều đó? C# copy reference chứ không copy value mà? Nếu bạn quan tâm, xin mời đọc tiếp. Nếu không, hãy an tâm như thế là đủ.

Rườm rà? Bạn không thích lặp lại đoạn mã này với tất cả các event, chẳng hạn khi bạn có quá nhiều event (Custom1, Custom2, v.v)? Có thể dùng extension method để làm cho code gọn đẹp hơn nữa, nhưng hẹn bài khác😀.

Vì sao vừa có event, vừa có delegate

Để ý rằng, với delegate, chúng ta cũng có các toán tử +=, –=, và cũng invoke được các delegate đã add, tương tự như event. Vậy tại sao chúng ta lại phải tạo event mà không dùng luôn delegate? Bởi vì nếu dùng delegate, sẽ có hai tình huống không mong đợi sau:

  • Subscriber override các subscriber khác bằng toán tử =. Chẳng hạn, một cách vô tình, lệnh subscribe được viết là … = … Kết quả là tất cả các delegate đã add vào CustomEventHandler trước đó sẽ bị xóa.
  • Subscriber có thể raise event bằng cách gọi delegate. Trong khi việc này lẽ ra chỉ nên được thực hiện bởi publisher.

Event thực chất được xây dựng dựa trên delegate, nhưng không cho phép các tình huống trên xảy ra. Khi khai báo một event, trình dịch sẽ ngầm tạo cho chúng ta một biến delegate private trong chính class chứa event. Lưu ý là event là một khái niệm ở mức CIL, vì vậy nó không đơn thuần chỉ là một wrapper cho delegate. Bạn có thể tham khảo đoạn mã dưới đây (từ quyển Essential C# 4.0), mô tả một cách sơ lược những gì trình dịch sẽ làm.

public delegate void CustomEventHandler(object sender, CustomEventArgs a);

private CustomEventHandler customEventHandler;

public void add_CustomEventHandler(CustomEventHandler handler) { 
  System.Delegate.Combine(customEventHandler, handler); 
}

public void remove_CustomEventHandler(CustomEventHandler handler) { 
  System.Delegate.Remove(customEventHandler, handler); 
}

public event CustomEventHandler customEventHandler { 
  add { add_customEventHandler(value) } 
  remove { remove_customEventHandler(value) } 
}

Và delegate là một immutable type

Để dễ hiểu, hãy xét kiểu string, cũng immutable, và cũng hỗ trợ toán tử += như delegate:

string s1 = "old"; 
string s2 = s1; 
s1 += “new”;

s2 vẫn sẽ là “old”, vì khi gán s1 += “new”, một chuỗi mới sẽ được tạo ra với giá trị là “oldnew”, và s1 sẽ trỏ sang chuỗi mới đó. Chuỗi s2, tất nhiên vẫn trỏ tới chuỗi cũ. Bây giờ xem lại phần copy trong raise event, bạn sẽ thấy vấn đề hoàn toàn sáng tỏ.

(Xóa phần immutable object, vì HM muốn viết nó thành một bài riêng)

Tags:
  1. Tháng Mười 29, 2010 lúc 11:05 chiều

    Good post! Bài viết khá tốt, tuy nhiên nếu đối tượng độc giả bạn nhắm tới là beginners thì bạn nên giải thích rõ hơn về mối liên hệ giữa event và delegate (delegate định nghĩa signature cho hàm xử lý sự kiện của event). Bài viết sau đi sâu hơn vào chi tiết sự khác biệt giữa delegate và event, có thể dùng để tham khảo (tuy nhiên yêu cầu kiến thức căn bản về event):

    http://wormtech.wordpress.com/2010/10/25/c-va-t%e1%bb%ab-khoa-event/

  2. Tháng Mười 30, 2010 lúc 11:17 sáng

    hân hạnh làm quen😀

  3. Thành
    Tháng Mười Một 12, 2010 lúc 10:55 chiều

    Anh cho em hỏi làm thế nào để bọc được code C# trong thẻ thế kia, anh có thể gửi code cho em qua email dc ko ah

  4. Tháng Mười Một 12, 2010 lúc 10:59 chiều
  5. Tháng Mười Một 13, 2010 lúc 5:01 chiều

    Bài viết rất hay, cảm ơn bạn nhiều vì đã chia sẻ!

  1. No trackbacks yet.

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s

%d bloggers like this: