C# 委托与事件的区别

1.什么是委托?
委托可以把一个方法代入另一个方法,相当于指向函数的指针,换句话说,委托相当于一个函数指针,而事件就相当于保存委托的数组。
总的来说,委托是一个类,该类内部维护着一个字段,指向一个方法。
委托的声明:public delegate void DoDelegate();
通过委托执行方法

namespace ConsoleAppCSharp
{
	class Program
    {
        static void Main(string[] args)
        {
            DelegateExample delegateExample = new DelegateExample();
            delegateExample.DoFunction();
        }
    }
    class DelegateExample
    {
        public delegate void DoDelegate(string valueStr);
        internal void DoFunction()
        {
            //声明一个委托变量,并把已知方法作为构造函数的参数
            DoDelegate doDelegate = new DoDelegate(Test);
            //通过委托的静态方法Invoke触发委托
            doDelegate?.Invoke("传入委托的值!");
        }

        void Test(string valueStr)
        {
            Console.Write($"valueStr={valueStr}");
        }
    }
}	

1.在CLR运行时,DoDelegate实际上是一个类,该类的构造函数有一个参数类型,这个参数类型就是Test方法,并且提供了一个实例Invoke方法,用来触发委托执行;
2.委托DoDelegate定义了方法的参数和返回值类型;
3.通过委托DoDelegate的构造函数,可以将符合的方法赋值给委托;
4.调用委托的实例方法Invoke执行方法。
委托执行方法的另外一种方式:委托变量(参数列表)

namespace ConsoleAppCSharp
{
	class Program
    {
        static void Main(string[] args)
        {
            DelegateExample delegateExample = new DelegateExample();
            delegateExample.DoFunction();
        }
    }
    class DelegateExample
    {
        public delegate void DoDelegate(object sender, EventArgs e);
        internal void DoFunction()
        {
            //声明一个委托变量,并将已知方法作为构造函数的参数
            DoDelegate doDelegate = new DoDelegate(Test);
            object sender = 888;
            EventArgs e = new EventArgs();
            doDelegate(sender, e);
        }
        void Test(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
    }
}	

1.委托DoDelegate的参数列表和Test方法的参数列表保持一致;
2.委托DoDelegate中的参数object sender通常表示动作的发起者,EventArgs e表示动作所带的参数。
实际上,事件就是采用委托变量(参数列表)形式执行方法。
2.什么是事件?
事件是基于委托的,为委托提供一个订阅或发布的机制。事件是一种特殊的委托,调用事件和委托是一样的。
事件可以被看作是委托类型的一个变量,通过事件注册、取消多个委托和方法。
事件的声明:
public event 委托类型 事件名称;
如:public event DoDelegate DoEvent;
通过事件执行方法

namespace ConsoleAppCSharp
{
	class Program
    {
        static void Main(string[] args)
        {
            DelegateExample delegateExample = new DelegateExample();
            delegateExample.DoFunction();
        }
    }
    class DelegateExample
    {
       public delegate void DoDelegate(object sender, EventArgs e);
        public event DoDelegate DoEvent;
        internal void DoFunction()
        {
            //声明一个委托变量,并将已知方法作为构造函数的参数
            DoDelegate doDelegate = new DoDelegate(Test);
            object sender = 888;
            EventArgs e = new EventArgs();
            DoEvent += new DoDelegate(doDelegate);
            DoEvent(sender, e);
        }
        void Test(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
}	

1.声明事件DoEvent,事件的类型是DoDelegate委托;
2.通过+=为事件注册委托;
3.通过DoDelegate的构造函数为事件注册委托实例;
4.采用委托变量(参数列表)形式,然事件执行方法。
通过+=还可以为事件注册多个委托

namespace ConsoleAppCSharp
{
	class Program
    {
        static void Main(string[] args)
        {
            DelegateExample delegateExample = new DelegateExample();
            delegateExample.DoFunction();
        }
    }
    class DelegateExample
    {
       public delegate void DoDelegate(object sender, EventArgs e);
        public event DoDelegate DoEvent;
        internal void DoFunction()
        {
            //声明一个委托变量,并将已知方法作为构造函数的参数
            DoDelegate doDelegate = new DoDelegate(Test);
            DoDelegate doDe = new DoDelegate(TestExample);
            object sender = 888;
            EventArgs e = new EventArgs();
            //事件注册多个委托
            DoEvent += new DoDelegate(doDelegate);
            DoEvent += new DoDelegate(doDe);
            DoEvent(sender, e);
        }
        void Test(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
        void TestExample(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
}	

通过+=为事件注册一个或多个委托实例,实际上还可以为事件直接注册方法。
事件直接注册方法

namespace ConsoleAppCSharp
{
	class Program
    {
        static void Main(string[] args)
        {
            DelegateExample delegateExample = new DelegateExample();
            delegateExample.DoFunction();
        }
    }
    class DelegateExample
    {
        public delegate void DoDelagate(object sender, EventArgs e);
        public event DoDelagate DoEvent;
        internal void DoFunction()
        {
            object sender = 888;
            EventArgs e = new EventArgs();
            //为事件注册多个委托
            DoEvent += Test;
            DoEvent += TestExample;
            DoEvent(sender, e);
        }
        void Test(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
        void TestExample(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
}	

通过EventHandler执行方法
EventHandler的源码:public delegate void EventHandler(object sender, EventArgs e);
从源码中可以看出,EventHandler是一个委托。使用EventHandler来执行多个方法。

namespace ConsoleAppCSharp
{
	class Program
    {
        static void Main(string[] args)
        {
            DelegateExample delegateExample = new DelegateExample();
            delegateExample.DoFunction();
        }
    }
    class DelegateExample
    {
        public event EventHandler DoEvent;
        internal void DoFunction()
        {
            object sender = 888;
            EventArgs e = new EventArgs();
            //为事件注册多个委托
            DoEvent += Test;
            DoEvent += TestExample;
            DoEvent(sender, e);
        }
        void Test(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
        void TestExample(object sender, EventArgs e)
        {
            Console.Write($"valueStr={sender}");
        }
}	

总的来说:
1.委托是一个类,可以实例化,通过委托的构造函数把方法赋值给委托实例;
2.触发委托有两种方式:委托实例.Invoke(参数列表)和委托实例(参数列表);
3.事件可看作是一个委托类型的变量;
4.+=为事件注册多个委托实例或多个方法;
5.-=为事件减少多个委托实例或多个方法;
5.EventHandler是一个委托。
3.委托与实例的区别
1.事件只能在方法的外部进行声明,而委托在方法的外部和内部都可以进行声明;
2.事件只能在类的内部进行触发,不能在类的外部进行触发。而委托在类的内部和外部都可触发;
3.委托一般用于回调,而事件一般用于外部接口。在观察者模式中,被观察者可在内部声明一个事件作为外部观察者注册的接口。

你可能感兴趣的:(C#)