我们先从单纯的委托开始研究。MSDN上给委托定义为:委托是一种定义方法签名的类型。 当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联。 您可以通过委托实例调用方法。 这三句话的意思表明了委托是一种类型,但是一种很特殊的类型,包含参数,返回值,一般类前面会有一个class修饰,但是委托前面用delegate;在实例化委托这个类型时需要与一个具体的方法相关联,而且这个方法的参数,返回值必须与委托定义的参数和返回值类型、个数一致。考虑现实中的一个现象,大贪官一般不自己*,会通过他的助手或者其他人间接*,这里贪官和他的助手之间会形成一个委托关系,大贪官可以定义成一个委托,助手*可以定义为一种方法。
这里面为了方便先定义个贪官类、助手类、贪官委托
namespace testcsharp3._0
{
public delegate void EventHandler();//大贪官委托,不包含任何参数,返回值为空
class tanguan //大贪官类,里面还什么也没有
{ }
}
namespace testcsharp3._0
{
class zhushou //定义助手类,里面包含一个静态方法,注意方法的参数和返回值与贪官的委托兼容
{
public static void suohui()
{
Console.WriteLine("贪官要出去旅游,通过助手帮其*1000元!");
}
}
}
static void Main(string[] args)
{
tanguan tg = new tanguan();//实力化一个贪官类
EventHandler weituo = new EventHandler(zhushou.suohui);//实例化一个委托,与zhushou类中的suohui方法关联起来
weituo();//执行委托
Console.ReadLine();
}
运行结果:贪官要出去旅游,通过助手帮其*1000元!
到此个最简单的委托例子就实现了,当然这个例子没有任何用处,呵呵。大家注意到,上面*这个动作实际上是通过main()函数里面的weituo()执行的。可能还是需要贪官给助手提示,助手才去*,这样的助手显然是不合理的。情况应该是一旦贪官缺钱花(这个事情发生可能使随机的),助手就要帮其去*,这样子贪官才会喜欢。与我们编程中点击一个按钮控件,就会触发一个事件一样。因此为了改进这种贪官的需求,我们有必要引入事件机制,一旦缺钱花的事件发生,助手就开始行动,呵呵!
class tanguan
{
public delegate void EventHandler();//大贪官委托,不包含任何参数,返回值为空
public event EventHandler nomoney;//贪官缺钱事件,与官的委托联系起来
public void nomoneyhappen()
{
nomoney();//触发这个缺钱事件
}
}
static void Main(string[] args)
{
tanguan tg = new tanguan();//实力化一个贪官类
tg.nomoney += new tanguan.EventHandler(tg_nomoney);//注册一个缺钱的事件
tg.nomoneyhappen();//执行函数,引发缺钱事件发生
Console.ReadLine();
}
static void tg_nomoney()//缺钱事件发生后,要干的事情
{
zhushou.suohui();//调用助手来要钱
}
运行后输出:贪官要出去旅游,通过助手帮其*1000元!
上面的代码就是将事件与委托联系起来了,但是这样的时间没有任何的参数传递,假如一个助手要帮好几个官处理要钱的事情,他必须知道是谁缺钱了,当他要到钱后就可以给谁,所以这种情况下,触发的事件对象应该清楚。
public string tanguanname { get; set; }//给贪官这个类加个名字属性,便于助手找
public delegate void NameEventHandler(object sender, EventArgs e);//大贪官委托,包含一个object的参数和空的EventArgs参数,sender就是引起事件的对象
public event NameEventHandler namenomoney;
public void nomoneyhappen()
{
//触发这个缺钱事件
namenomoney(this, null);//传递当前对象过去
}
static void Main(string[] args)
{
tanguan tg = new tanguan() {tanguanname="A" };//实力化一个A贪官类
tg.namenomoney += new tanguan.NameEventHandler(tg_namenomoney); //注册一个缺钱的事件
tg.nomoneyhappen();//执行函数,引发缺钱事件发生
Console.ReadLine();
}
static void tg_namenomoney(object sender, EventArgs e)
{
tanguan t = sender as tanguan;//获得到底是哪个官缺钱
Console.WriteLine(t.tanguanname);
zhushou.suohui();
}
上面的运行输出为:A 贪官要出去旅游,通过助手帮其*1000元!
如果把main()函数中的 tanguan tg = new tanguan() {tanguanname="B" };//实力化一个B贪官类 ,那么结果就是 B 贪官要出去旅游,通过助手帮其*1000元!
同样的如果想传递更多参数信息,我们可以继承EventArgs类,定义自己的参数类型,这样传递的信息会更丰富哦!
通过上面的事件与委托代码 我们知道程序流程是:先定义一个委托,接着定义一个委托的事件,在调用方里面注册一个事件,并实例化一个委托,与这个注册的事件关联起来,定义委托的方法,在方法中执行你想要干的事情。 一旦我们触发了事件(这里我们通过代码触发的,像button这样的标准控件可以通过鼠标点击触发),就会执行委托的方法。
下面我们研究委托的进化。像上面那些注册事件的代码 tg.namenomoney += new tanguan.NameEventHandler(tg_namenomoney); //注册一个缺钱的事件
发现这里的方法名称tg_namenomoney其实作用不大,C#中完全可以用匿名方法代替,因此代码可以改为
tg.namenomoney += delegate(object sender, EventArgs e)//匿名方法
{
tanguan t = sender as tanguan;//获得到底是哪个官缺钱
Console.WriteLine(t.tanguanname);
zhushou.suohui();
};
匿名方法的引用,让委托变得直接了当,不用绕个弯子了,至于 匿名方法编译成什么了,要研究下编译后的代码,这个还没仔细研究过,有待完善。。。
微软那帮人觉得上面那样搞代码还不够简洁,如是又产生了lambda表达式
tg.namenomoney += (object sender, EventArgs e)=>
{
tanguan t = sender as tanguan;//获得到底是哪个官缺钱
Console.WriteLine(t.tanguanname);
zhushou.suohui();
};
这个和上面的执行结果一样。注意=>这个是在lambda里面产生的新的符号,左边表示参数列表,右边执行语句,lambda表达式的参数既可以是显示类型化的,也可以是隐式的。编译器可以更具上下文推断出来。在我看来 这些都是委托演变而来的,只不过微软把编译器做的更牛了,让我们少写了很多代码,编译器编译后的代码估计还原始的委托差不多(没有研究过,不知道对不对)
有了lambda表达式后,微软又整出来个隐式类型的东东,我们经常说C#是强类型语言,任何变量的定义都必须指定类型,但是在现实中有一种这样的情况,我们需要的是数据,并不关注他的类型是什么,从数据库检索出来的数据,也许和某个实体类属性是一一对应的,但是我们并不需要所有这些字段的数据,我们可能利用其中的两个字段的数据,以前的搞法是,在新定义一个类型,然后一个个实例化这个类,赋值给属性。现在如果有了隐式类型,我们就可以省下从新定义类的工作量了。如:var peoplename=“huxing”; 编译器会自动的推断出这个变量的类型是字符串,说到底还是编译器干的活,牛逼!
有了隐士类型,有了lambda表达式,微软就水到渠成的推出了Linq,先看下面这段代码
public static List<person> listperson = new List<person>
{
new person{name="guoyuanwei",age=600},
new person{name="wanjianbang",age=600},
new person{name="xiaoyunxi",age=600},
new person{name="huxing",age=600},
new person{name="hujingtao",age=100},
new person{name="wenjiabao",age=80},
};
public static void showallperson(List<person> listp,int count)
{
var man = from p in listp
where p.age > 300
select new { manname = p.name, manage = p.age };//lambda表达式,linq语句
foreach(var v in man)
{
Console.WriteLine(v.manname + ":" + v.manage.ToString());
}
}
如果在main()函数里面调用showallperson()就会输出 年龄大于300的人的名字,如果采取传统的c#代码,我们可能这样做
把 showallperson部分改为用foreach遍历
public static void showallperson(List<person> listp,int count)
{
foreach (person p in listp)
{
if(p.age>300)
Console.WriteLine(p.name + ":" + p.age.ToString());
}
}
咋看上去代码还少些了,当然我的这个例子比较短,也许看不出啥来,但是在复杂的逻辑中lambda表达式就会显出他的威力。
好了,就写到这里,要干活了哦,时间紧,任务重啊!下次在整理整理,写的不好,望大家指正。