C#中的委托和事件简单理解

时间:2022-03-20 05:49:44

以下是个人粗浅的理解:

委托delegrate,可以看做是将方法的封装成类型的工具。如(代码摘自http://www.cnblogs.com/firstyi/archive/2008/02/01/1060923.html):

 class DelegateTest
C#中的委托和事件简单理解    
{
C#中的委托和事件简单理解        
delegate string Convert(string text);
C#中的委托和事件简单理解
C#中的委托和事件简单理解        
public void Test()
C#中的委托和事件简单理解        
{
C#中的委托和事件简单理解            
string strText = "123451234512345";
C#中的委托和事件简单理解
C#中的委托和事件简单理解            Test2(ConvertA, strText);
C#中的委托和事件简单理解            Test2(ConvertB, strText);
C#中的委托和事件简单理解            Test2(ConvertC, strText);
C#中的委托和事件简单理解
C#中的委托和事件简单理解            Console.ReadLine();
C#中的委托和事件简单理解        }

C#中的委托和事件简单理解
C#中的委托和事件简单理解        
private void Test2(Convert convert, string strText)
C#中的委托和事件简单理解        
{
C#中的委托和事件简单理解            Console.WriteLine(convert(strText));
C#中的委托和事件简单理解        }

C#中的委托和事件简单理解
C#中的委托和事件简单理解        
public string ConvertA(string strText)
C#中的委托和事件简单理解        
{
C#中的委托和事件简单理解            
return strText.Replace("1""A");
C#中的委托和事件简单理解        }

C#中的委托和事件简单理解        
public string ConvertB(string strText)
C#中的委托和事件简单理解        
{
C#中的委托和事件简单理解            
return strText.Replace("1""B");
C#中的委托和事件简单理解        }

C#中的委托和事件简单理解        
public string ConvertC(string strText)
C#中的委托和事件简单理解        
{
C#中的委托和事件简单理解            
return strText.Replace("1""C");
C#中的委托和事件简单理解        }

C#中的委托和事件简单理解    }

以上代码中定义了一个delegrate,该委托将类似 string method(string str)的方法封装成一个类型Convert(其中method表示方法名)。该类型可以作为参数传递给Test2(Convert convert,string str),其中Convert表示类型,convert 表示变量,于是就可以像一般的方法那样调用了,如Test2(ConvertA,strText),ConvertA 是一个方法,同时也是Convert类型的变量。同时,也可以定义匿名方法,如

    class DelegateTest
    {
        delegate string Convert(string text);

        public void Test()
        {
            string strText = "123451234512345";

            Test2(delegate(string strText2)
                {
                    return strText2.Replace("1", "A");
                }, strText);
            Test2(delegate(string strText2)
                {
                    return strText2.Replace("1", "B");
                }, strText);
            Test2(delegate(string strText2)
                {
                    return strText2.Replace("1", "C");
                }, strText);

            Console.ReadLine();
        }

        private void Test2(Convert convert, string strText)
        {
            Console.WriteLine(convert(strText));
        }
    }

代码中专门定义ConverA,ConvertB ConvertC等方法,直接用一个delegrate代替,其实质是一样的。

 

事件

事件可以理解为封装了委托的属性,让我们在类的外部不对对委托任意操作,只能用“+=”或者“-=“等,要触发事件,可以在类的内部定义一个public方法来触发事件,其实也就是调用方法。没有委托也就没有事件,事件的类型也就是委托所定义的类型,可以把委托所定义的类型的变量,也就是具体方法赋值给事件。

如下

DelegrateTest delegrateTest = new DelegrateTest();
while (true)
{
Console.WriteLine("Input the string ");
string str = Console.ReadLine();
if (str.Contains('1'))
{
delegrateTest.eventConvert +=new DelegrateTest.Convert(delegrateTest.ConvertA);
delegrateTest.OnEventConvert(str);
}
if (str.Contains('2'))
{
delegrateTest.eventConvert += delegrateTest.ConvertB;//这一句同上面delegrateTest.eventConvert +=new DelegrateTest.Convert(delegrateTest.ConvertA)一样,只不过上面使用了委托的初始化函数;
delegrateTest.OnEventConvert(str);

}
if (str.Contains('3'))
{
delegrateTest.eventConvert += delegrateTest.ConvertC;
delegrateTest.OnEventConvert(str);

}
}

 

在类的外部不能直接触发事件,只能通过delegrateTest的内部方法OnEventConvert()来触发事件。DelegrateTest类如下

  class DelegrateTest
        {
            public  delegate string Convert(string str);
            public event Convert eventConvert;
            public  string ConvertA(string str)
            {
                return str.Replace('1', 'A');
            }
            public  string ConvertB(string str)
            {
                return str.Replace('2', 'B');
            }
            public  string ConvertC(string str)
            {
                return str.Replace('3', 'C');
            }

            public  void Test(Convert convert, string str)
            {
                Console.WriteLine(convert(str));
            }
            public void OnEventConvert(string str)
            {
                if(this.eventConvert!=null)
                {
                    Console.WriteLine(
                    eventConvert(str));
                }
            }
        }

 

说的这里,很多人会觉得奇怪,为什么我们在.Net中使用的事件不是这样的呢?主要在于.Net对事件有如下规定(摘自http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html Jimmy Zhang 的博客,写的简单易懂,大家可以去看一下)

  • 委托类型的名称都应该以EventHandler结束。
  • 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
  • 事件的命名为 委托去掉 EventHandler之后剩余的部分。
  • 继承自EventArgs的类型应该以EventArgs结尾。

将上面的代码规范化

 class Program
    {
        static void Main(string[] args)
        {
            DelegrateTest delegrateTest = new DelegrateTest();
            while (true)
            {
                Console.WriteLine("Input the string ");
                string str = Console.ReadLine();
                if (str.Contains('1'))
                {
                    delegrateTest.eventConvert += new DelegrateTest.Convert(delegrateTest.ConvertA);
                    delegrateTest.OnEventConvert(delegrateTest,new ConvertEventArgs(str));
                }
                if (str.Contains('2'))
                {
                    delegrateTest.eventConvert += delegrateTest.ConvertB;
                    delegrateTest.OnEventConvert(delegrateTest,new ConvertEventArgs(str));

                }
                if (str.Contains('3'))
                {
                    delegrateTest.eventConvert += delegrateTest.ConvertC;
                    delegrateTest.OnEventConvert(delegrateTest,new ConvertEventArgs(str));

                }
            }
            //Timer timer = new Timer(1000);

            ////下面两句 的效果是一样的,只不过第一句使用了时间的初始化函数初始化了一个方法
            //timer.Elapsed += new System.Timers.ElapsedEventHandler(ShowTime);
            //timer.Elapsed += ShowTime;

            //timer.Start();
            //Console.ReadLine();
        }
        //static void ShowTime(object sender,EventArgs e)
        //{
        //    Console.Clear();
        //    Console.WriteLine(DateTime.Now.ToString("yyyy年MM月dd日 hh:mm:ss"));
        //}
        class ConvertEventArgs : EventArgs
        {
            public string str;
            public ConvertEventArgs( string s)
            {
                str = s;
            }
        }
        class DelegrateTest
        {
            public  delegate void Convert(object sender, ConvertEventArgs str);
            public event Convert eventConvert;
            public  void ConvertA(object sender,ConvertEventArgs e)
            {
                Console.WriteLine(e.str.Replace('1', 'A'));
            }
            public  void ConvertB(object sender,ConvertEventArgs e)
            {
                Console.WriteLine(e.str.Replace('2', 'B'));
            }
            public void ConvertC(object sender, ConvertEventArgs e)
            {
                Console.WriteLine(e.str.Replace('3', 'C'));
            }

            //public  void Test(Convert convert, string str)
            //{
            //    Console.WriteLine(convert(this,new));
            //}
            public void OnEventConvert(object sender, ConvertEventArgs e)
            {
                if(this.eventConvert!=null)
                {
                    eventConvert(sender, e);
                }
            }
        }
    }
    

因为我们要传递参数,所以ConvertEventArgs类,该类继承了EventArgs基类,如果不用传递参数,则上面的ConvertEventArgs可以用EventArgs代替。

以上是我自己对委托和事件的粗浅看法。