C# - 委託與事件

ShenHaoCore發表於2024-05-09

委託與事件

委託

class Program
{
    static void Main(string[] args)
    {
        Publisher publisher = new Publisher("籃球先鋒報");

        Observer observerA = new Observer("老A");
        publisher.Magazine += observerA.RecvMagazine;

        Observer observerB = new Observer("老B");
        publisher.Magazine += observerB.RecvMagazine;

        publisher.PublishMagezine();
        //或者使用下面的方式  區別就是一個在定義的內部觸發,一個在外部觸發
        publisher.Magazine?.Invoke(publisher.magazineName);
        Console.ReadKey();
    }
}

public class Observer
{
    private string name;
    public Observer(string name)
    {
        this.name = name;
    }

    public void RecvMagazine(string message)
    {
        Console.WriteLine($"{this.name} recv {message}, 仔細讀了一番");
    }
}

public class Publisher
{
    public string magazineName;
    public Publisher(string magazineName)
    {
        this.magazineName = magazineName;
    }

    public delegate void MagazineDelegate(string message);
    public MagazineDelegate Magazine;

    public void PublishMagezine()
    {
        Magazine?.Invoke(this.magazineName);
    }
}

事件

class Program
{
    static void Main(string[] args)
    {
        Publisher publisher = new Publisher("籃球先鋒報");

        Observer observerA = new Observer("老A");
        publisher.Magazine += observerA.RecvMagazine;

        Observer observerB = new Observer("老B");
        publisher.Magazine += observerB.RecvMagazine;

        publisher.PublishMagezine();
        //下面的方式會出現編譯錯誤  只允許在定義的內部觸發,不允許在外部觸發
        publisher.Magazine?.Invoke(publisher.magazineName);
        Console.ReadKey();
    }
}

public class Observer
{
    private string name;
    public Observer(string name)
    {
        this.name = name;
    }

    public void RecvMagazine(string message)
    {
        Console.WriteLine($"{this.name} recv {message}, 仔細讀了一番");
    }
}

public class Publisher
{
    public string magazineName;
    public Publisher(string magazineName)
    {
        this.magazineName = magazineName;
    }

    public delegate void MagazineDelegate(string message);
    public event MagazineDelegate Magazine;

    public void PublishMagezine()
    {
        Magazine?.Invoke(this.magazineName);
    }
}

經典面試題

貓叫、老鼠跑了,主人醒來了

class Program
{
    static void Main(string[] args)
    {
        Cat cat = new Cat();
        Mouse m = new Mouse(cat);
        People p = new People(cat);
        cat.Scream();
    }
}

public class Cat
{
    public delegate void ScreamHandler();
    public event ScreamHandler OnScream;

    public void Scream()
    {
        Console.WriteLine("貓叫了一聲");
        OnScream?.Invoke();
    }

}

public class Mouse
{
    public Mouse(Cat c)
    {
        c.OnScream += () => { Console.WriteLine("老鼠跑了"); };
    }
}

public class People
{
    public People(Cat c)
    {
        c.OnScream += () => { Console.WriteLine("主人醒來了"); };
    }
}

//輸出:
//貓叫了一聲
//老鼠跑了
//主人醒來了

委託與事件的區別

  1. 事件基於委託,但並非委託 可以把事件看成委託的代理。在使用者看來,只有事件,而沒有委託。
  2. 事件是對委託的包裝 保護委託欄位,對外不開放。所以外部物件沒法直接操作委託。提供了Add和Remove方法,供外部物件訂閱事件和取消事件。事件的處理方法在物件外部定義,而事件的執行是在物件的內部。至於事件的觸發,何時何地無所謂。

什麼時候使用委託與事件?

如果一個委託不需要再其定義的類之外被觸發,那麼就可以將其轉化為事件,這樣可以保證它不會在外部被隨意觸發。

相關文章