2010-06-17 28 views
5

Tại sao tôi không thể sử dụng sự kiện được khai báo trong Cơ sở từ Phụ?Sử dụng sự kiện và ủy quyền trong phân lớp

class Program 
{ 
    static void Main(string[] args) 
    { 
     Sub sub = new Sub(); 
     sub.log += new Base.logEvent(sub_log); 
     sub.go(); 
    } 

    static void sub_log(string message, int level) 
    { 
     Console.Out.WriteLine(message + " " + level); 
    } 
} 

public abstract class Base 
{ 
    public delegate void logEvent(String message, int level); 

    public event logEvent log; 
} 

public class Sub : Base 
{ 

    public void go() 
    { 
     log("Test", 1); // <-- this wont compile 
    } 
} 
+0

Duplicate - http://stackoverflow.com/questions/756237/c -raising-an-inherited-event –

Trả lời

6

Sự kiện chỉ có thể được gọi từ lớp khai báo chúng.

Từ bên ngoài định nghĩa của một lớp (ngay cả trong lớp học có nguồn gốc), bạn chỉ có thể đăng ký và hủy đăng ký từ event. Bên trong lớp, trình biên dịch chỉ cho phép bạn nâng cao sự kiện. Đây là hành vi theo thiết kế của C# (thực sự thay đổi một chút trong C# 4 - Chris Burrows describes the changes on his blog).

Những gì bạn muốn làm ở đây là cung cấp phương thức RaiseLogEvent() trong lớp cơ sở, điều này sẽ cho phép lớp dẫn xuất gọi sự kiện này.

public abstract class Base 
{ 
    public delegate void logEvent(String message, int level); 

    public event logEvent log; 

    protected void RaiseLogEvent(string msg, int level) 
    { 
     // note the idomatic use of the copy/test/invoke pattern... 
     logEvent evt = log; 
     if(evt != null) 
     { 
      evt(msg, level); 
     } 
    } 
} 

Ngoài ra, bạn nên cân nhắc sử dụng loại giao dịch EventHandler<> thay vì tạo loại sự kiện của riêng mình khi có thể.

+0

Vì vậy, thay vì tuyên bố một đại biểu, tôi tạo một lớp con của EventArgs chứa thông điệp của tôi và loglevel? Tại sao điều đó tốt hơn? – klundby

+0

@klundy: Mẫu chuẩn cho trình xử lý sự kiện trong .NET là cung cấp một người gửi và một đối tượng đại diện cho các đối số. Điều này cho phép các thuê bao của các envents duy trì sự nhất quán trong chữ ký của họ, và làm giảm sự nhầm lẫn về những thông số được mong đợi. Với phương thức co/contra-variance của C# 4, việc xử lý sự kiện chung chung trở nên dễ dàng hơn khi trình xử lý không quan tâm đến các đối số hoặc người gửi. Những gì tôi đã làm trong nhiều trường hợp là tạo ra một lớp 'genericArgs ' chung mà thừa kế từ 'EventArgs' và cho phép tôi chuyển dữ liệu đến trình xử lý ... nhưng đó chỉ là một lựa chọn kiểu. – LBushkin

+0

Đây là một trong những thiết kế ngôn ngữ vô dụng, bẻ khóa, không có dấu vết nhất mà tôi từng thấy trong một thời gian dài. –

2

Vì sự kiện chỉ có thể được gọi từ lớp khai báo. Chỉ cần tạo một phương thức trong lớp cơ sở để gọi nó là:

protected virtual RaiseLogEvent(string s, int i) 
{ 
    log(s, i); 
} 

Vì vậy, bạn có thể sử dụng phương thức này trong việc tạo lớp và thậm chí ghi đè lên lớp.

Lưu ý khác, tôi đặc biệt khuyên bạn nên làm theo các hướng dẫn thiết kế cho các sự kiện và tạo lớp EventArgs riêng và sử dụng đại biểu EventHandler<T>.

0

Có, bạn có thể khai báo các sự kiện trong một lớp cơ sở để chúng cũng có thể được nâng lên từ các lớp dẫn xuất.

Tạo phương thức gọi được bảo vệ cho sự kiện. Bằng cách gọi phương thức gọi này, các lớp dẫn xuất có thể gọi sự kiện.

Đọc dưới đây cách tiêu chuẩn để khai báo các sự kiện trong một lớp cơ sở để họ cũng có thể được huy động từ các lớp thừa kế:

Raise Base Class Events in Derived Classes

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