add 和 remove 关键字用于定义一个在客户端代码订阅你的事件时调用的自定义事件访问器。

你必须同时提供这两个访问器(若提供了 add 访问器,则必须提供 remove 访问器;反之亦然)。

通常不需要提供自己的自定义事件访问器。大多数情况下,使用声明事件时由编译器自动生成的访问器就足够了。

下面的例子提供了两个(两组 add 和 remove)事件的访问器,它演示了如何处理不太常见的情况:类继承自两个或多个接口,且每个接口都具有相同名称的事件。在这种情况下,你必须为至少其中一个事件提供显式接口实现。为事件编写显式接口实现时,便必须编写 add 和 remove 事件访问器。在这种情况下,编译器不提供事件的通常访问器。

通过提供自己的访问器,可以指定两个事件是由类中的同一个事件表示,还是由不同事件表示。例如,如果根据接口规范应在不同时间引发事件,则可以将每个事件与类中的单独实现关联起来。在下面的例子中,订阅者通过将 shape 引用转换为 IShape 或 IDrawingObject 来确定他们将接收哪个 OnDraw 事件。

internal class Program
    {
        static void Main(string[] args)
            {
                Shape xz = new ( );
                Subscriber1 zi1 = new ( xz );
                Subscriber2 zi2 = new ( xz );
                xz . Draw ( );
                Console . WriteLine ( zi1 . ToString ( ) );
                Console . WriteLine ( zi2 . ToString ( ) );

                Console . WriteLine ( "按任意键退出……" );
                Console . ReadKey ( );
        }
    }

public interface IDrawingObject
    {
        // 在勾画对象之前先引发这个事件
        event EventHandler OnDraw;
    }

public interface IShape
    {
        // 在勾画对象之后在引发这个事件
        event EventHandler OnDraw;
    }

// 基类事件继承了两个接口,每个接口都有一个 OnDraw 事件
public class Shape : IDrawingObject , IShape
    {
        // 为每个接口事件创建事件
        event EventHandler? PreDrawEvent;
        event EventHandler? PostDrawEvent;

        private readonly Lock objectLock = new ( );

        // 需要显式接口实现
        // 将 IDrawingObject 的事件与 PreDrawEvent 关联
        #region IDrawingObjectOnDraw
            event EventHandler IDrawingObject . OnDraw
                {
                    add
                        {
                            lock ( objectLock )
                                {
                                    PreDrawEvent += value;
                                }
                        }
                    remove
                        {
                            lock ( objectLock )
                                {
                                    PreDrawEvent -= value;
                                }
                        }
                }
        #endregion
        // 需要显式接口实现
        // 将 IShape 的事件与 PostDrawEvent 关联
        event EventHandler IShape . OnDraw
            {
                add
                    {
                        lock ( objectLock )
                            {
                                PostDrawEvent += value;
                            }
                    }
                remove
                    {
                        lock ( objectLock )
                            {
                                PostDrawEvent -= value;
                            }
                    }
            }

        // 为了简单起见,这个方法实现了两个接口
        public void Draw ( )
            {
                // 在勾画对象前引发 IDrawingObject 的事件
                PreDrawEvent? . Invoke ( this , EventArgs . Empty );

                Console . WriteLine ( "勾画一个形状。" );

                // 在勾画对象后引发 IShape 的事件
                PostDrawEvent? . Invoke ( this , EventArgs . Empty );
            }
    }

public class Subscriber1
    {
        // 将 xz(形状)对象引用为 IDrawingObject
        public Subscriber1 ( Shape xz )
            {
                IDrawingObject d = ( IDrawingObject ) xz;
                d . OnDraw += d_OnDraw;
            }

        void d_OnDraw ( object sender , EventArgs e )
            {
                Console . WriteLine ( "子 1 接收 IDrawingObject 事件。" );
            }

        public override string ToString ( )
            {
                return "子 1 的 ToString";
            }
        }

// 将 xz(形状)对象引用为 IShape
public class Subscriber2
    {
        public Subscriber2 ( Shape xz )
            {
                IShape d = ( IShape ) xz;
                d . OnDraw += D_OnDraw;
            }

        void D_OnDraw ( object sender , EventArgs e )
            {
                Console . WriteLine ( "子 2 接收 IShape 事件。" );
            }

        public override string ToString ( )
            {
                return "子 2 的 ToString";
            }
    }

兔子码农
4 声望1 粉丝

一个酒晕子