2009-04-03 50 views
9

Dưới đây là chương trình tôi đã sử dụng để kiểm tra. It in (như dự kiến):Sự kiện ảo hoạt động như thế nào trong C#?

Raise A 
Event from A 
Raise B 
Event from B 

Bây giờ, nếu chúng ta thay đổi hai dòng đầu tiên của Main là:

 A a = new B(); 
     B b = new B(); 

Chương trình sẽ in:

Raise A 
Raise B 
Event from B 

đó là cũng được mong đợi, vì sự kiện ghi đè ẩn trường sao lưu riêng tư trong lớp cơ sở và do đó các sự kiện được kích hoạt bởi lớp cơ sở không hiển thị cho các máy khách của lớp dẫn xuất.

Bây giờ tôi thay đổi các dòng cùng:

B b = new B(); 
A a = b; 

và chương trình bắt đầu in:

Raise A 
Raise B 
Event from A 
Event from B 

gì đang xảy ra?

class A 
{ 
    public virtual event EventHandler VirtualEvent; 
    public void RaiseA() 
    { 
     Console.WriteLine("Raise A"); 
     if (VirtualEvent != null) 
     { 
      VirtualEvent(this, EventArgs.Empty); 
     } 
    } 
} 
class B : A 
{ 
    public override event EventHandler VirtualEvent; 
    public void RaiseB() 
    { 
     Console.WriteLine("Raise B");    
     if (VirtualEvent != null) 
     { 
      VirtualEvent(this, EventArgs.Empty); 
     } 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(); 
     B b = new B(); 

     a.VirtualEvent += (s, e) => Console.WriteLine("Event from A"); 
     b.VirtualEvent += (s, e) => Console.WriteLine("Event from B"); 

     a.RaiseA(); 
     b.RaiseB(); 
    } 
} 
+0

Điều "Sự kiện ảo trong C#: đã xảy ra sự cố" - http://www.viva64.com/en/b/0453/ –

Trả lời

12

Chúng tôi có một trường hợp duy nhất (B) trong đó có các lĩnh vực sau:

  • A.VirtualEvent: null
  • B.VirtualEvent: Hai xử lý sự kiện

Các cuộc gọi đến a.RaiseA()chỉ in "Tăng A" - nhưng không có gì khác, bởi vì trường riêng trong A là rỗng.

Gọi tới b.RaiseB() in ba dòng còn lại, vì sự kiện đã được đăng ký hai lần (một lần để in "Sự kiện từ A" và một lần để in "Sự kiện từ B").

Điều đó có hữu ích không?

EDIT: Để làm cho nó rõ ràng hơn - hãy nghĩ về sự kiện ảo như một cặp phương pháp ảo. Nó rất giống như thế này:

public class A 
{ 
    private EventHandler handlerA; 

    public virtual void AddEventHandler(EventHandler handler) 
    { 
     handlerA += handler; 
    } 

    public virtual void RemoveEventHandler(EventHandler handler) 
    { 
     handlerA -= handler; 
    } 

    // RaiseA stuff 
} 

public class B : A 
{ 
    private EventHandler handlerB; 

    public override void AddEventHandler(EventHandler handler) 
    { 
     handlerB += handler; 
    } 

    public override void RemoveEventHandler(EventHandler handler) 
    { 
     handlerB -= handler; 
    } 

    // RaiseB stuff 
} 

Bây giờ nó rõ ràng hơn? Nó không phải là khá như vậy vì theo tôi biết bạn không thể ghi đè chỉ "một phần" của một sự kiện (nghĩa là một trong các phương pháp) nhưng nó mang lại ấn tượng chung phù hợp.

+0

Điều đó chắc chắn giúp, ngoại trừ việc không rõ ràng a.VirtualEvent + = (s, e) => Console.WriteLine ("Sự kiện từ A"); thậm chí còn có thể thấy B.VirtualEvent để đăng ký nó? – Prankster

+0

+1, bang! đó là âm thanh của tâm trí tôi quay trở lại. Tôi duỗi bộ não của mình đến giới hạn của nó đang nhìn chằm chằm vào mã OP đang cố gắng quấn quanh não tôi. Ngay cả khi tôi nhìn thấy con bọ, tôi cũng không thể nói nó một cách sáng suốt. –

+0

B.VirtualEvent ẩn A.VirtualEvent, vì các sự kiện không đa hình. –

2

Bạn đã ghép hai trình xử lý sự kiện cho cùng một sự kiện. Vì A và B đang trỏ đến cùng một đối tượng, khi bạn gọi hàm b.RaiseB(), cả hai trình xử lý sự kiện sẽ được kích hoạt. Vì vậy, trước tiên bạn đang gọi RaiseA là một phương thức basecals. Điều đó in Raise A. Nó sau đó không thực sự bắn ra sự kiện bởi vì nó là null. Sau đó, bạn đang nâng B nhưng TWO trình xử lý được kết nối với nó, do đó đầu tiên in Raise B và khi sự kiện kích hoạt, cả hai trình xử lý đều được gọi.

0

Hãy thử làm cho chức năng RaiseA của bạn được bảo vệ + ảo.

Quy tắc chung: Nếu lớp dẫn xuất ghi đè truy cập sự kiện, nó cũng phải ghi đè lên hàm gọi sự kiện.

+0

"Nếu lớp dẫn xuất ghi đè truy cập sự kiện, nó cũng phải ghi đè lên hàm gọi sự kiện." Bạn có thể chỉ cho tôi phần đặc tả ngôn ngữ nêu rõ điều này không? – Prankster

+0

Hãy xem trang này: http://msdn.microsoft.com/en-us/library/8627sbea(VS.80).aspx –

+0

Có một câu lệnh "Gói sự kiện trong một phương thức ảo được bảo vệ để kích hoạt các lớp dẫn xuất để nâng cao sự kiện. " –

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