2009-04-23 28 views
8

Tôi có một lớp cơ sở DockedToolWindow: Biểu mẫu và nhiều lớp bắt nguồn từ DockedToolWindow. Tôi có một lớp container chứa và gán các sự kiện cho các đối tượng DockedToolWindow, tuy nhiên tôi muốn gọi các sự kiện từ lớp con.Tăng sự kiện cơ bản trong các lớp học có nguồn gốc C#

Tôi thực sự có câu hỏi về cách triển khai những gì mà MSDN site này đang yêu cầu tôi thực hiện. Phần dưới đây được đưa ra cho tôi những vấn đề:

// The event. Note that by using the generic EventHandler<T> event type 
    // we do not need to declare a separate delegate type. 
    public event EventHandler<ShapeEventArgs> ShapeChanged; 

    public abstract void Draw(); 

    //The event-invoking method that derived classes can override. 
    protected virtual void OnShapeChanged(ShapeEventArgs e) 
    { 
     // Make a temporary copy of the event to avoid possibility of 
     // a race condition if the last subscriber unsubscribes 
     // immediately after the null check and before the event is raised. 
     EventHandler<ShapeEventArgs> handler = ShapeChanged; 
     if (handler != null) 
     { 
      handler(this, e); 
     } 
    } 

chắc ví dụ này biên dịch và các công trình, nhưng khi tôi thay thế "ShapeChanged" với "Move" (một sự kiện tôi có được từ phát sinh từ Mẫu), nó lỗi nói rằng tôi không thể di chuyển bên phải mà không cần + = hoặc - =. Tôi cũng đã xóa các thẻ chung của ShapeEventArgs.

Bất kỳ nghi ngờ nào về lý do tại sao tính năng này không hoạt động? Sự khác nhau giữa sự kiện được khai báo trong lớp học và sự kiện được kế thừa là gì?

Trả lời

12

Bạn không thể trực tiếp kích hoạt sự kiện lớp cơ sở.Đây chính xác là lý do tại sao bạn phải đặt phương thức OnShapeChangedprotected thay vì private của mình.

Sử dụng base.OnMove() để thay thế.

+0

Tôi thấy rằng OnMove() sẽ giải quyết điều này, tuy nhiên làm thế nào không thể gọi OnMove() explicity khi nó cần thiết tôi có thể? Tôi không biết khung thực sự gọi là đại biểu Di chuyển, và có lẽ là ẩn từ tôi anyway. – Balk

+3

OnMove kích hoạt sự kiện Move, giống như cách OnShapeChanged kích hoạt sự kiện ShapeChanged trong mã của bạn. Đây là một mô hình phổ biến để thêm các thành viên được bảo vệ để kích hoạt các sự kiện, làm cho chúng hiển thị với các lớp dẫn xuất. Trong trường hợp đó, tiền tố "On" thường được thêm vào (OnMove, OnClick, v.v.) – Groo

+0

Để xem nơi khung thực sự kích hoạt sự kiện Move, hãy sử dụng công cụ Reflector (http://www.red-gate.com/products/reflector /) để lấy mã nguồn cho phương thức Form.OnMove. – Groo

3

Sự khác biệt là phạm vi. Bên trong lớp của bạn, bạn có thể kiểm soát cách các đại biểu sự kiện của bạn được xử lý, tuy nhiên, lớp của bạn không thể kiểm soát những gì lớp cơ sở đang làm. Nó có thể đang làm một số công cụ đằng sau hậu trường điên rồ với sự kiện và các bộ xử lý của nó. Nếu bạn chỉ cần "gán lại" sự kiện Move, bạn sẽ xóa danh sách đại biểu multicast cho sự kiện.

Tôi đoán họ đặt giới hạn trình biên dịch vì điều này là một thực hành rất không an toàn, và về cơ bản sẽ cung cấp cho bất kỳ lớp hậu duệ nào khả năng phá hủy mô hình sự kiện của cha mẹ.

4

Từ ngôn ngữ C# spec, phần 10,7 (nhấn mạnh thêm):

Trong văn bản chương trình của lớp hoặc struct chứa tuyên bố một sự kiện, sự kiện nhất định có thể được sử dụng như các lĩnh vực. Để được sử dụng theo cách này, một sự kiện không được trừu tượng hoặc bên ngoài, và không được bao gồm một cách rõ ràng các khai báo sự kiện-accessor. Sự kiện như vậy có thể được sử dụng trong bất kỳ ngữ cảnh nào cho phép một trường. Trường có chứa một đại biểu (§15) trong đó đề cập đến danh sách các trình xử lý sự kiện đã được thêm vào sự kiện. Nếu không có trình xử lý sự kiện nào được thêm vào, trường này chứa null.

Do đó, lý do bạn không thể xử lý sự kiện Di chuyển như trường là nó được xác định theo một loại khác (trong trường hợp này là lớp cha của bạn). Tôi đồng ý với suy đoán của @ womp rằng các nhà thiết kế đã thực hiện lựa chọn này để ngăn chặn khỉ không mong muốn với sự kiện này. Có vẻ như xấu để cho phép các loại không liên quan (các kiểu không bắt nguồn từ kiểu khai báo sự kiện) để làm điều này, nhưng ngay cả đối với các kiểu có nguồn gốc, nó có thể không được mong muốn. Họ có lẽ sẽ phải bao gồm cú pháp để cho phép khai báo sự kiện được thực hiện private hoặc protected liên quan đến cách sử dụng kiểu trường, do đó, tôi đoán là họ đã chọn không cho phép hoàn toàn.

1

Bạn chỉ cần mã bạn đã đăng trong lớp mà bản thân sự kiện được xác định. Tất cả các lớp dẫn xuất chỉ đơn giản là gọi OnShapeChanged() hoặc OnMove() trực tiếp, không cần sao chép, vì vậy bạn không nên viết mã đó trong tất cả các lớp của bạn (vì sự kiện Move được định nghĩa trong cơ sở).

Nếu bạn cần làm một số loại xử lý trong lớp dẫn xuất (có thể bạn cần phải fiddle với lớp bộ sưu tập của bạn?), Bạn ghi đè cuộc gọi OnXXX ảo và làm công cụ trước khi gọi base.OnXXX(). Trong bài viết MSDN, lớp Circle tương ứng với lớp DockedToolWindow của bạn. Cùng một mẫu sẽ có sẵn cho các lớp học có nguồn gốc của bạn.

+0

Tôi thấy rằng OnMove() sẽ giải quyết điều này, tuy nhiên làm thế nào không thể gọi OnMove() explicity khi nó cần thiết tôi có thể? Tôi không biết khung thực sự gọi là đại biểu Di chuyển, và có lẽ là ẩn từ tôi anyway. – Balk

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