《精通C#》委托与事件(10章)

委托可用来解耦以及状态变化的实时通知,以及其他的一些作用,但是经验所限,目前还未遇见。网上的大多数例子都是类似于,使用委托,然后用console返回方法的返回值,有时候会在想,委托的通知如果是这样的话,那么我可以用return以及out或者ref等就可以获得方法的返回值,其实也没错,但是要注意return一用上,就等于将return下面的代码全部停止运行,out与ref也是要在方法运行完了之后才会返回值,也就是说,我如果需要在方法运行中返回值的话,以上三个是无法做到的,但是委托就可以,因为委托是以方法为参数的,调用委托就是在执行委托所指向的方法,状态信息的处理可以再改方法内进行,但这种行为也可以直接在方法中就行调用另外一个方法来解决,效果是一样的,但是耦合度上就会有差别,当然还有其他的作用,我还没接触到,就不发声了。

使用委托需先使用delegate关键字定义,之后需实例化和声明,实例声明是需要注意,方法和委托的返回值和参数类型和个数需要一致才行,例:

public dalegate void DelegateTest(int x,int y);

main(){

DalegateTest dt=new DalegateTest(DelegateMethod);

dt();//或者dt.Invoke();

}

public static void DelegateMethod(int a,int b)

{

console.writeline(a+b);

}

C#中还有一个方法组转换的简便方法,这个方法允许开发者在调用以委托为参数的方法时,直接写入方法名,而不需要创建一个委托对象,例:

static void Main(string[] args)
        {
            SimpaleDelegate s = new SimpaleDelegate();

            SimpaleDelegate.Handlers h = new SimpaleDelegate.Handlers(s.sub);
            s.Register(new SimpaleDelegate.Handlers(new SimpaleDelegate().sub));//原始写法
            s.Register(new SimpaleDelegate().Add);//方法组转换

            s.Register(h);
            s.result3();
            s.RemoveRegister(h);
            s.result3();
            Console.ReadKey();
        }

namespace Delegate
{
   public class SimpaleDelegate
    {

//定义一个委托
        public delegate int Handlers(int x, int y);

//声明一个委托变量
        private Handlers handlers;

//注册一个委托
        public void Register(Handlers h)
        {
            handlers += h;
        }

//注销一个委托
        public void RemoveRegister(Handlers h)
        {
            handlers -= h;
        }
        public int Add(int a,int b)
        {
            Console.WriteLine("this is Add:{0}",a + b);
           return 0;
        }
       public void result3()
        {
           Console.WriteLine(handlers(2, 5));
        }
    }
}
例中的+=和-=就是委托中的多路广播的简写方式,在使用-=时要注意,要先创建委托对象,并保存在本地,在注销的时候要调用本地保存的对象,如若不然,将无法完成预期中的注销,即将sub注销。

同时需要注意到我在类中定义了一个私有的委托变量,为什么不是公有的呢?原因在于若是定义为公有的,调用者就可以直接访问委托,对委托变量重新赋值,这样的话就等于删除了当前所要调用的方法列表。

委托中还有一类泛型委托,类似public delegate void GenericDelegate<T>(T tag);这是定义了一个无返回值的,仅有一个参数的委托,在使用它的时候记得要注明类型名称,如:GenericDelegate<int> GD=new  GenericDelegate<int>(className);

上面说过,使用一个委托,我们需要先定义,在声明,但是这样通常会构成大量的只适用于当前项目的自定义委托,大部分时候我们都只是需要接受一组数据并返回一个值的委托,因此微软给我们内置了Action<>与Func<>,两者都可以指向多至16个参数的方法,区别在于Action<>返回void,Func<>的返回值的类型由Func的最后一个类型参数决定。

前面说了把委托定义为公有的坏处,这个坏处在事件中是不存在的,事件就是利用event关键字定义委托对象:public delegate void delegateName();public event delegateName eventName; ,这是定义,编译器在处理event关键字时会自动提供注册和注销以及任何必要的委托类型成员,这些委托成员变量总是声明为私有的,且声明必然只能在类的级别出现,且不可用static修饰,因此触发事件无法直接调用他们。这样说起来,事件就像是加了盔甲的委托一样。还可以使用EventHandler<T>来定义事件,类似,大部分的用法也与委托差不多,还记得前面说过,多路广播就是使用+=或者-=添加或者移除委托,例:eventName+=委托对象,这也是事件的调用方法,不过符号的左边是事件的名称,符号的右边是委托。同时因为方法组转换的存在,在符号左边也可直接写上符合事件规则的方法名称,例:eventName+=方法名称。

微软推荐的事件模式是类似public static void Name(object sender,EventArgs e);sender是对当前对象的一个引用,若是要传回数据,则需要自己重新定义一个EventArgs类型的实例,例:

public class CarEventArgs:EventArgs

{

public readonly string msg;//readonly为只读字段,只能在运行初始进行赋值,之后都无法进行修改,因而需在构造函数内进行赋值

public CarEventArgs(string message)

{

msg=message;

}

}

当调用者调用一个事件时,往往需要定义一个唯一的与相关联委托签名匹配的方法,但是这个方法很少被委托以为的任何程序调用,如此看来,手工定义一个由委托对象调用的方法就有点浪费,于是,我们可以这样做:

eventName+=delegate{//这里面是委托对象调用的方法内容};,这是一个不带参数的,带参数的是:eventName+=delegate(参数类型 参数{,...}){//这里面是委托对象调用的方法内容};,这样写就不用再去定义特定的处理程序,这叫做匿名方法。匿名方法不能访问定义它们的方法的ref和out参数,匿名方法中的变量不能与外部方法的变量重名。这时就要说说lambda表达式了,它是匿名方法更简单的写法,使用"=>"符号,例:

namespace Lambda
{
   public class Program
    {
        static void Main(string[] args)
        {
            EventClass e = new EventClass();
            e.SetMathHandler((string msg, int result) => { Console.WriteLine("Message:{0},Result:{1}", msg, result); });
            e.eventName += () => { Console.WriteLine("this is lambda"); };//这是供事件调用的代码
            e.Add(10, 10);
           
            Console.ReadLine();
        }
    }
}

namespace Lambda
{
   public class EventClass
    {
        public delegate void DelegateName();
        public event DelegateName eventName;
        public delegate void MathMessage(string msg, int result);
        private MathMessage mmDelegate;
        public void SetMathHandler(MathMessage taget)
        {
            mmDelegate = taget;
        }
        public void Add(int x,int y)
        {
            if (mmDelegate != null)
                mmDelegate.Invoke("Add", x + y);
            eventName();
        }
    }
}
结果是:

简单翻译(string msg, int result) => { Console.WriteLine("Message:{0},Result:{1}", msg, result);的意思就是,参数msg和result会被表达式console处理。

 

转载于:https://www.cnblogs.com/Lin-Li/p/5961795.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值