2011-01-21 23 views
7

Tôi có lớp sau đây, trong đó có một sự kiện nào được gọi là LengthChanged:Làm thế nào để tham khảo một sự kiện trong C#

class Dimension 
{ 
    public int Length 
    { 
     get 
     { 
      return this.length; 
     } 
     set 
     { 
      if (this.length != value) 
      { 
       this.length = value; 
       this.OnLengthChanged(); 
      } 
    } 

    protected virtual void OnLengthChanged() 
    { 
     var handler = this.LengthChanged; 
     if (handler != null) 
     { 
      handler (this, System.EventArgs.Empty); 
     } 
    } 

    public event System.EventHandler LengthChanged; 

    private int length; 
} 

Tôi muốn để có thể đăng ký/xử lý unregister cho sự kiện này trong một phương pháp gọi là Observer , không biết gì về lớp Dimension. Tôi đã đưa ra hai kịch bản, không ai trong số đó là thực sự thỏa mãn:

  1. Xác định một giao diện ILengthChanged với sự kiện LengthChanged, thì chắc chắn rằng Dimension thực hiện ILengthChanged. Sau đó, tôi phải cung cấp một triển khai phương pháp Observer cho mọi giao diện mà tôi xác định. Điều này bằng cách không có cách nào đủ chung chung. Tôi thực sự muốn có thể chỉ đơn giản là vượt qua trong một tham chiếu đến một sự kiện System.EventHandler.

  2. Sử dụng System.Action<System.EventHandler> callbacks đăng ký và unregistering xử lý sự kiện trong phương pháp Observer, chỉ cần như thế:

    lớp Foo { public void Observer (System.Action đăng ký, System.Action unregister) { đăng ký (this.MyEventHandler);

    // keep track of the unregister callback, so that we can unregister 
        // our event handler later on, if needed... 
    } 
    
    private void MyEventHandler(object sender, System.EventArgs e) 
    { 
        ... 
    } 
    

    }

mà sau đó sẽ được gọi như thế này:

Foo foo = ...; 
Dimension dim = ...; 

foo.Observer (x => dim.LengthChanged += x, x => dim.LengthChanged -= x); 

và trong đó, khi thực hiện, thực sự sẽ kết thúc dây sự kiện LengthChanged với xử lý sự kiện nội bộ MyEventHandler . Nhưng điều này không phải là rất thanh lịch. Tôi rất muốn có thể viết thay thế này:

Foo foo = ...; 
Dimension dim = ...; 

foo.Observer (dim.LengthChanged); 

nhưng tôi không biết làm thế nào để đạt được điều này. Có lẽ tôi đang thiếu một cái gì đó thực sự rõ ràng ở đây? Tôi đoán rằng một số ma thuật dynamic có thể làm thủ thuật, bằng cách nào đó, nhưng điều này sẽ không thực thi kiểm tra kiểu biên dịch: Tôi không muốn người dùng của Observer chuyển các tham chiếu đến các sự kiện không đáp ứng chữ ký sự kiện System.EventHandler.

Trả lời

10

Thật không may là không thực sự là một cách để làm điều này. Sự kiện không phải là công dân hạng nhất trong .NET nói chung - mặc dù F # cố gắng quảng cáo cho họ ở đó.

Hoặc chuyển vào đại biểu đăng ký/hủy đăng ký hoặc sử dụng chuỗi chỉ tên của sự kiện. (Sau này thường ngắn hơn, nhưng rõ ràng là ít an toàn hơn trong thời gian biên dịch.)

Đó là cách tiếp cận mà Reactive Extensions mất - nếu có cách làm sạch hơn, tôi chắc chắn họ sẽ sử dụng: (

+0

Nếu những người như Erik Meijer đã không thể đưa ra các giải pháp sạch hơn, tôi nghi ngờ rằng thực sự, không có cách nào khác để làm điều đó. Thật buồn ... Cảm ơn bạn đã trả lời nhanh chóng, Jon. –

2

Sự kiện không được cho là được chuyển vào một phương pháp khác, tuy nhiên, bạn có thể chuyển giao quyền đại biểu thành một phương pháp khác, có lẽ, những gì bạn đang tìm kiếm chỉ là đại biểu công khai thay vì sự kiện.

Nếu bạn thay đổi sự kiện của bạn để này

public System.EventHandler LengthChanged; 

Bạn chỉ có thể vượt qua LengthChanged để Observer như thế này

Foo foo = ...; 
Dimension dim = ...; 
foo.Observer (dim.LengthChanged); 
+0

Cảm ơn bạn đã đề xuất. Không, tôi không thể vượt qua đại biểu thay vì sự kiện; sự kiện có thể thực hiện các 'sett' và' remove' setters và thực sự phải được định nghĩa là một sự kiện C# 'chính thức. –

+0

@Pierre tôi thấy .. trong trường hợp đó, những gì tôi sẽ làm là để khai báo một lớp wrapper đại biểu. Phương thức khởi tạo của lớp đó lấy một đại biểu. Lớp này có AddHandler ảo() và RemoveHandler ảo(). Nó cũng có một phương thức Invoke() để gọi đại biểu. Để làm cho nó trông tao nhã hơn, bạn có thể định nghĩa toán tử + =, - =, + và -, gọi AddHandler và RemoveHandler của bạn. Thay thế sự kiện LengthChanged của Dimension của bạn bằng lớp wrapper này. Đối với trường hợp bạn cần "thêm" và "loại bỏ" setters, chỉ cần ghi đè lên các lớp học AddHandler và RemoveHandler phương pháp của lớp học. Chỉ cần 2 xu của tôi. Tôi đã làm tương tự. –

+0

giải pháp tốt đẹp ... Tôi sẽ phải suy nghĩ lại. 1 cho hack tốt đẹp này. –

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