Delegate
   
    delegate是C#中很重要的语法。
    
    委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。
    
    声明了delegate的属性都会继承自Delegate类。
    
    使用单播委托类似C和C++的函数指针,但委托是面向对象和类型安全的(封装成delegate对象)。
    
    使用多播委托类似观察者模式(发布/订阅模式)。实际上源码使用得最多的也是多播模式。但委托的通知实现方法绑定是基于函数签名(duck type)而非接口。相比传统的观察者模式实现更加灵活,有点像guava的Eventbus,而且实现更加优雅。
    
    delegate不仅可以绑定外部方法,内部方法,静态方法。还能绑定匿名委托和lambda函数。可以使用 “=” 赋值委托方法,也可以使用“+=”和“-=”添加和去除委托方法。使用非常灵活方便。例子:
   
using System;
using System.Xml.Serialization;
namespace TestDelegateAndEvent
{
    class TestDelagateAndEvent
    {
        public static void innerStaticSayHello(String name)
        {
            Console.WriteLine($"innerStaticSayHello:hello {name}");
        }
        public void innerSayHello(String name)
        {
            Console.WriteLine($"innerSayHello:hello {name}");
        }
        /*
         * 声明delegate 
         */
        public delegate void SayHelloDelegate(String name);
        /*
         * 声明delegate对象
         */
        public SayHelloDelegate sayHelloDelegate;
        public event SayHelloDelegate sayHeloEvent;
        public void activateSayHelloDelegate(String name)
        {
            sayHelloDelegate?.Invoke(name);
        }
        public void activateSayHelloEvent(String name)
        {
            sayHeloEvent?.Invoke(name);
        }
    }
    class Test
    {
        public static void outerSayHello(String name)
        {
            Console.WriteLine($"outerSayHello:hello {name}");
        }
        static void Main(string[] args)
        {
            TestDelagateAndEvent obj = new TestDelagateAndEvent();
            /*
             * test delagate
             */
            //delegate 能使用 "="
            obj.sayHelloDelegate = obj.innerSayHello;
            obj.sayHelloDelegate += TestDelagateAndEvent.innerStaticSayHello;
            obj.sayHelloDelegate += Test.outerSayHello;
            obj.sayHelloDelegate += (name) =>
            {
                Console.WriteLine($"Lambda:hello {name}");
            };
            //delegate 能作为对象直接调用invoke
            Console.WriteLine("delegate 直接invoke");
            obj.sayHelloDelegate("小明");
            Console.WriteLine("delegate 在对象内部invoke");
            obj.activateSayHelloDelegate("小明");
        }
    }
}
    
    
    Event
   
    event在C#中是一种特殊的委托。
    
    在 C# Windows 窗体或 Web 应用程序中,控件事件的订阅和通知就是通过event来实现的。
    
    event的使用和delegate类似。在 .NET Framework 类库中,事件基于 EventHandler 委托和 EventArgs 基类。我们可以通过继承EventArgs基类自定义自己的事件参数,并通过继承EventHandler 委托或者使用范型自定义自己的窗体事件。举MSDN上的例子:
   
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Text;
namespace TestEvent
{
    /*
     * 自定义event 事件
     */
    public class ShapeEventArgs : EventArgs
    {
        public double NewArea
        {
            get;
        }
        public ShapeEventArgs(double area)
        {
            this.NewArea = area;
        }
    }
    /*
     * shape抽象类
     */
    public abstract class Shape
    {
        protected double _area;
        public double Area
        {
            get => _area;
            set => _area = value;
        }
        public event EventHandler<ShapeEventArgs> ShapeChanged;
        public abstract void Draw();
        protected virtual void OnShapeChange(ShapeEventArgs e)
        {
            ShapeChanged?.Invoke(this, e);
        }
    }
    public class Circle : Shape
    {
        private double _radius;
        public Circle(double radius)
        {
            _radius = radius;
            _area = 3.14 * _radius * _radius;
        }
        public override void Draw()
        {
            Console.WriteLine("Write a Circle!");
        }
        protected override void OnShapeChange(ShapeEventArgs e)
        {
            base.OnShapeChange(e);
        }
        public void Update(double d)
        {
            _radius = d;
            _area = 3.14 * _radius * _radius;
            OnShapeChange(new ShapeEventArgs(_area));
        }
    }
    public class Rectangle : Shape
    {
        private double _length;
        private double _width;
        public Rectangle(double length, double width)
        {
            _length = length;
            _width = width;
            _area = _length * _width;
        }
        public override void Draw()
        {
            Console.WriteLine("Write a Rectangle!");
        }
        protected override void OnShapeChange(ShapeEventArgs e)
        {
            base.OnShapeChange(e);
        }
        public void Update(double length,double width)
        {
            _length = length;
            _width = width;
            _area = _length * _width;
            OnShapeChange(new ShapeEventArgs(_area));
        }
    }
    public class ShapeContainer
    {
        private readonly  IList<Shape> _list;
        public ShapeContainer()
        {
            _list = new List<Shape>();
        }
        public void AddShape(Shape shape)
        {
            _list.Add(shape);
            shape.ShapeChanged += handleShapeChanged;
         
        }
        private void handleShapeChanged(object sender, ShapeEventArgs e)
        {
            if (sender is Shape shape)
            {
                Console.WriteLine($"Received event. Shape area is now {e.NewArea}");
                shape.Draw();
            }
            
        }
    }
    class Test
    {
        static void Main(string[] args)
        {
            ShapeContainer container = new ShapeContainer();
            Circle circle = new Circle(54);
            Rectangle rectangle = new Rectangle(12, 9);
            container.AddShape(circle);
            container.AddShape(rectangle);
            // Cause some events to be raised.
            circle.Update(57);
            rectangle.Update(7, 7);
        }
    }
}
    
    
    delegate和event的区别
   
    event是特殊的delegate。
    
    如果不基于EventHandler实现的event,跟delegate主要区别是event语法上多了一些限制。
    
    1.event事件只能使用”+=“或”-=“进行订阅和取消订阅操作。不能进行“=”赋值操作。也即是说订阅了一个事件只能在通过”-=”进行取消订阅,除此之外无其他方式。
    
    2.event事件触发只能通过事件所在对象内部触发。对象外部无法触发事件。而delegate能从对象外部对委托invoke。
    
    还是使用委托的例子:
   
......
        /*
         * 声明delegate 
         */
        public delegate void SayHelloDelegate(String name);
        /*
         * 声明delegate对象
         */
        public SayHelloDelegate sayHelloDelegate;
        public event SayHelloDelegate sayHeloEvent;
......
        static void Main(string[] args)
        {
            TestDelagateAndEvent obj = new TestDelagateAndEvent();
            /*
             * test delagate
             */
            //delegate 能使用 "="
            obj.sayHelloDelegate = obj.innerSayHello;
            obj.sayHelloDelegate += TestDelagateAndEvent.innerStaticSayHello;
            obj.sayHelloDelegate += Test.outerSayHello;
            obj.sayHelloDelegate += (name) =>
            {
                Console.WriteLine($"Lambda:hello {name}");
            };
            //delegate 能作为对象直接调用invoke
            Console.WriteLine("delegate 直接invoke");
            obj.sayHelloDelegate("小明");
            Console.WriteLine("delegate 在对象内部invoke");
            obj.activateSayHelloDelegate("小明");
            /*
             * test event
             */
            //event事件只能使用"+="或"-="
            //test.sayHeloEvent = test.innerSayHello;
            obj.sayHeloEvent += TestDelagateAndEvent.innerStaticSayHello;
            obj.sayHeloEvent += Test.outerSayHello;
            obj.sayHeloEvent += (name) =>
            {
                Console.WriteLine($"Lambda:hello {name}");
            };
            //event 只能在对象内部invoke
            //test.sayHeloEvent("小明");
            Console.WriteLine("event 在对象内部invoke");
            obj.activateSayHelloEvent("小明");
.......
    
    
    最后
   
    msdn委托guide:
    
     https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/delegates/
    
   
    msdn事件guide:
    
     https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/events/
     
    
   
 
