2009-06-30 65 views
35

我正在使用一个在C#中转发事件的类。我想知道是否有办法做 它需要较少的代码开销。在C中转发事件#

下面是我到目前为止的一个例子。

class A 
{ 
    public event EventType EventA; 
} 

class B 
{ 
    A m_A = new A(); 
    public event EventType EventB; 

    public B() 
    { 
     m_A.EventA += OnEventA; 
    } 

    public void OnEventA() 
    { 
     if(EventB) 
     { 
     EventB(); 
     } 
    } 
} 

A级引发原始事件。 B类将其作为EventB(它本质上是相同的事件)转发。 A类对其他模块是隐藏的,因此它们不能直接订阅EventA。

我想要做的是减少类B中用于转发事件的代码开销,因为通常没有真正处理类B中的事件。另外,我将有几个不同的事件,因此它需要写入B类中的很多OnEvent()方法只用于转发事件。

是否有可能自动地以某种方式链接到EventA EventB,所以我有这样的事情:

class B 
{ 
    A m_A = new A(); 
    public event EventType EventB; 

    public B() 
    { 
     m_A.EventA += EventB; // EventA automatically raises EventB. 
    } 
} 

我使用C#2.0编译器BTW。

+0

大问题,特别是因为你不应该忘记从EventA退订,否则可能会发生内存泄漏(即使A不再需要,对象B仍会保留在内存中)。 – dbkk 2009-06-30 21:01:08

回答

64

绝对:

class B 
{ 
    private A m_a = new A(); 

    public event EventType EventB 
    { 
     add { m_a.EventA += value; } 
     remove { m_a.EventA -= value; } 
    } 
} 

换句话说,在EventB订购/退订代码只是传递到EventA订购/退订请求。

但请注意,对于订阅了EventB的订阅者,这不允许您为事件提高。这就像直接将某人的地址传递给大众营销公司,而您的原始方式更像是亲自订阅大众营销公司,并允许人们要求您将邮件副本发送给他们。

+11

这确实意味着`B.EventB`的订户得到了错误的发件人('A`而不是`B`),但是 - 这可能很重要... – 2009-06-30 20:22:21

9

IMO,你的原始代码是(或多或少)是正确的。特别是,它允许您提供正确的sender(对于认为他们正在订阅B事件的用户,应该是B实例)。

有一些技巧,以减少开销在运行时,如果没有签约的情况下,但是这会增加更多代码:

class B { 
    A m_A = new A(); 
    private EventType eventB; 
    public event EventType EventB { 
     add { // only subscribe when we have a subscriber ourselves 
      bool first = eventB == null; 
      eventB += value; 
      if(first && eventB != null) m_A.EventA += OnEventB; 
     } 
     remove { // unsubscribe if we have no more subscribers 
      eventB -= value; 
      if(eventB == null) m_A.EventA -= OnEventB; 
     } 
    } 

    protected void OnEventB(object sender, EventArgsType args) { 
     EventType handler = eventB; 
     if(handler !=null) { 
     handler(this, args); // note "this", not "sender" 
     } 
    } 
}