在 C# 中转发事件

发布于 2024-07-25 16:16:48 字数 827 浏览 7 评论 0原文

我正在使用一个在 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 类中没有真正处理事件。此外,我还将有几个不同的事件,因此需要编写大量 OnEvent B 类中的 () 方法仅用于转发事件。

是否可以以某种方式自动将 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 编译器。

I'm using a class that forwards events in C#. I was wondering if there's a way of doing
it that requires less code overhead.

Here's an example of what I have so far.

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();
      }
   }
}

Class A raises the original event. Class B forwards it as EventB (which is essentially the same event). Class A is hidden from other modules so they can't subscribe to EventA directly.

What I'm trying to do is reduce the code overhead in class B for forwarding the event, as typically there's no real handling of the events in class B. Also I'll have several different events so it would require writing a lot of OnEvent() methods in class B that only serve to forward the events.

Is it possible to automatically link EventA to EventB in some way, so I'd have something like this:

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

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

I'm using a C# 2.0 compiler btw.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦醒时光 2024-08-01 16:16:48

绝对:

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

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

换句话说,Eve​​ntB 订阅/取消订阅代码只是将订阅/取消订阅请求传递给 EventA。

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

Absolutely:

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

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

In other words, the EventB subscription/unsubscription code just passes the subscription/unsubscription requests on to EventA.

Note that this doesn't allow you to raise the event just for subscribers who subscribed to EventB, however. It's like passing someone's address directly onto a mass marketing company, whereas your original way is more like subscribing to the mass marketing company yourself, and allowing people to ask you to send copies of the mails to them.

画骨成沙 2024-08-01 16:16:48

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) {
      eventB?.Invoke(this, args); // note "this", not "sender"

   }
}

IMO, your original code is (more or less) correct. In particular, it allows you to provide the correct sender (which should be the B instance for people who think they are subscribing to an event on B).

There are some tricks to reduce the overheads at runtime if the event isn't subscribed, but this adds more code:

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) {
      eventB?.Invoke(this, args); // note "this", not "sender"

   }
}
浅语花开 2024-08-01 16:16:48

这就是我的想法:

public interface IExampleConnection
{
    event ReceivedDataEventHandler ReceivedData;
}

public class ConnectionProxy: IExampleConnection
{
    private IExampleConnection _innerConnection;

    // dictionary to store the original event handler and the closure around it with our own handling logic
    private IDictionary<ReceivedDataEventHandler, ReceivedDataEventHandler> _receivedData = new Dictionary<ReceivedDataEventHandler, ReceivedDataEventHandler>();

    // helps protect access to the dictionary containing the event handlers 
    private object objectLock = new object();

    public ConnectionProxy(IExampleConnection innerConnection)
    {
        _innerConnection = innerConnection;
    }
    
    public event ReceivedDataEventHandler ReceivedData
    {
        add
        {
            lock (objectLock)
            {
                // use the original event handler `value` as a key in the dictionary
                // our custom handler becomes the value
                _receivedData.Add(value, (sender, args) =>
                {
                    // insert logic that you want to run before the original event handler

                    // call the original event handler
                    value(sender, args);

                    // insert logic that you want to run after the original event handler finishes

                });
                // add our handler to the dictionary by using the value as the key
                _innerConnection.ReceivedData += _receivedData[value];
            }
        }
        remove
        {
            lock (objectLock)
            {
                // use the incoming event handler `value` to lookup our wrapper around it
                _innerConnection.ReceivedData -= _receivedData[value];
            }
        }
    }
}

这比我通常想要的代码要多一些。 我怀疑有办法让它更简洁,但它对于我的目的来说已经足够好了。

This is what I came up with:

public interface IExampleConnection
{
    event ReceivedDataEventHandler ReceivedData;
}

public class ConnectionProxy: IExampleConnection
{
    private IExampleConnection _innerConnection;

    // dictionary to store the original event handler and the closure around it with our own handling logic
    private IDictionary<ReceivedDataEventHandler, ReceivedDataEventHandler> _receivedData = new Dictionary<ReceivedDataEventHandler, ReceivedDataEventHandler>();

    // helps protect access to the dictionary containing the event handlers 
    private object objectLock = new object();

    public ConnectionProxy(IExampleConnection innerConnection)
    {
        _innerConnection = innerConnection;
    }
    
    public event ReceivedDataEventHandler ReceivedData
    {
        add
        {
            lock (objectLock)
            {
                // use the original event handler `value` as a key in the dictionary
                // our custom handler becomes the value
                _receivedData.Add(value, (sender, args) =>
                {
                    // insert logic that you want to run before the original event handler

                    // call the original event handler
                    value(sender, args);

                    // insert logic that you want to run after the original event handler finishes

                });
                // add our handler to the dictionary by using the value as the key
                _innerConnection.ReceivedData += _receivedData[value];
            }
        }
        remove
        {
            lock (objectLock)
            {
                // use the incoming event handler `value` to lookup our wrapper around it
                _innerConnection.ReceivedData -= _receivedData[value];
            }
        }
    }
}

It's a bit more code than I would normally like. I suspect there's way to make it more concise, but it worked well enough for my purposes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文