Delegate(委托与事件)
系统自带的泛型委托
Action 无参数无返回值
Action<T> 没有返回值,最多有16个参数
Action<int> func = e => Console.WriteLine(e);
func(123)
Func 具有返回值,最多有16个参数
Func<int> f = () => 123;
Console.WriteLine(f() + 1);
List<string> list = new List<string>("赵晓虎,王小虎,乐虎,老虎,东北虎,华南虎".Split(','));
foreach (string item in list.Where(e => e.Contains("华"))) //Where,输入参数为字符串,返回参数为布尔
{
Console.WriteLine(item);
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public char Sex { get; set; } public override string ToString()
{
return string.Format("{0},{1}", Name, Age);
}
} ------------------------------------------------------------------
public delegate int MyCompareHandler(Person p1, Person p2); public class Program
{
static void Main(string[] args)
{
MyCompareHandler MyCompare = null;
Person[] ps =
{
new Person() { Age=, Name="赵晓虎", Sex='男' },
new Person() { Age=, Name="波波", Sex='男' },
new Person() { Age=, Name="杨茜", Sex='女' },
new Person() { Age=, Name="马伦", Sex='男' }
};
// 排序
// 比较
// int n = string.Compare("a", "b");
// MyCompare = CompareByAge;
//MyCompare = CompareByName; //if (MyCompare != null)
//{
// int num = MyCompare(ps[0], ps[1]);
//} // MyCompareHandler compare = CompareByAge; // Sort(ps, compare); // Sort(ps, CompareByName); Sort(ps, (a, b) => string.Compare(a.Name, b.Name));
Sort(ps, (a, b) => a.Age - b.Age);
}
//冒泡排序 public static void Sort(Person[] ps, MyCompareHandler compare)
{
if (compare == null) return;
for (int i = ; i < ps.Length - ; i++)
{
for (int j = ; j < ps.Length - i - ; j++)
{
if (compare(ps[j], ps[j + ]) > )
{
Person pTemp = ps[j];
ps[j] = ps[j + ];
ps[j + ] = pTemp;
}
}
}
} //public static int CompareByAge(Person p1, Person p2)
//{
// // n1 > n2 => n1 - n2 > 0
// return p1.Age - p2.Age;
//}
//public static int CompareByName(Person p1, Person p2)
//{
// return string.Compare(p1.Name, p2.Name);
//}
}
委托计算器
public class Calculator
{
public static int AdditionMethod(int num1, int num2)
{
return num1 + num2;
}
public static int SubtractionMethod(int num1, int num2)
{
return num1 - num2;
}
public static int MultiplicationMethod(int num1, int num2)
{
return num1 * num2;
}
public static int DivisionMethod(int num1, int num2)
{
return num1 / num2;
}
} public delegate int MyCalculator(int n1, int n2); class Program
{
static void Main(string[] args)
{
// 需要什么?
// 委托
// 实现加减乘除的方法 Console.WriteLine("请输入数字");
int num1 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("请输入运算符");
string oper = Console.ReadLine();
Console.WriteLine("请输入数字");
int num2 = Convert.ToInt32(Console.ReadLine()); MyCalculator cal = null; switch (oper)
{
case "+": cal = Calculator.AdditionMethod; break;
case "-": cal = Calculator.SubtractionMethod; break;
case "*": cal = Calculator.MultiplicationMethod; break;
case "/": cal = Calculator.DivisionMethod; break;
} if (cal != null)
{
Console.WriteLine("{0}{1}{2}={3}", num1, oper, num2, cal(num1, num2));
} Console.ReadKey();
}
}
委托计算器
-------------------------------------------------------------
窗体传值
public partial class Form1 : Form
{
Random r = new Random();
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
ChangeColor();
} private void ChangeColor()
{
this.BackColor = Color.FromArgb(r.Next(), r.Next(), r.Next()); } int i = ;
private void timer1_Tick(object sender, EventArgs e)
{
//i += 10;
// this.BackColor = Color.FromArgb(i, 256 - i, i); } private void button2_Click(object sender, EventArgs e)
{
// 创建子窗体
Form2 f = new Form2(); // 订阅方法
f.MyFunc += ChangeColor; f.Show();
}
} //////////////////////////////////////////////////////////////////////////
public partial class Form2 : Form
{
public event Action MyFunc; public Form2()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
if (MyFunc != null)
{
MyFunc();
}
}
}
-------------------------------------------------------------
有些时候委托绑定的方法比较简单,而且在代码中可能只是用一次
-> 如果不用定义,直接写一个表达式或者一个赋值操作就可以完成这个功能就好了
-> 匿名方法
-> 语法:
委托类型 委托名 = delegate(参数列表) { /* 方法体 */ };
2、 SumHandler sum = (n1, n2) => n1 + n2;
Lambda表达式
参数 => 方法体
=> goes to
参数类型在不冲突的情况下可以省略
如果参数只有一个,可以使用
e => ...
没有参数的时候,可以使用
() => ...
方法体如果只有一句话,省略{}
方法体如果只有一句话,并且有返回值,可以省略return
---------------------------------------------------------------
与函数指针相比,delegate有许多函数指针不具备的优点。首先,函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数。
委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。
使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。
调用(invoke)委托,相当于调用委托所绑定的方法,一个委托可以绑定多个方法,使用"+="就可以向委托中添加新的方法,使用"-="可以从委托中删除方法
利用鸿门宴解释委托与事件:http://www.cnblogs.com/yinqixin/p/5056307.html
结合delegate的实现,我们可以将自定义事件的实现归结为以下几步:
1.定义delegate对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象。
2.定义事件参数类,此类应当从System.EventArgs类派生。如果事件不带参数,这一步可以省略。
3.定义事件处理方法,它应当与delegate对象具有相同的参数和返回值类型。
4. 用event关键字定义事件对象,它同时也是一个delegate对象。
5.用+=操作符添加事件到事件队列中(-=操作符能够将事件从队列中删除)。
6.在需要触发事件的地方用调用delegate的方式写事件触发方法。一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。名字是OnEventName。
7. 在适当的地方调用事件触发方法触发事件。下面是一个简单的例子:
using System;
public class EventTest
{
// 步骤1,定义delegate对象
public delegate void MyEventHandler(object sender, System.EventArgs e);
// 步骤2省略
public class MyEventCls
{
// 步骤3,定义事件处理方法,它与delegate对象具有相同的参数和返回值类// 型
public void MyEventFunc(object sender, System.EventArgs e)
{
Console.WriteLine("My event is ok!");
}
}
// 步骤4,用event关键字定义事件对象
private event MyEventHandler myevent;
private MyEventCls myecls;
public EventTest()
{
myecls = new MyEventCls();
// 步骤5,用+=操作符将事件添加到队列中
this.myevent += new MyEventHandler(myecls.MyEventFunc);
}
// 步骤6,以调用delegate的方式写事件触发函数
protected void OnMyEvent(System.EventArgs e)
{
if(myevent != null)
myevent(this, e);
}
public void RaiseEvent()
{
EventArgs e = new EventArgs();
// 步骤7,触发事件
OnMyEvent(e);
}
public static void Main()
{
EventTest et = new EventTest();
Console.Write("Please input ''a'':");
string s = Console.ReadLine();
if(s == "a")
{
et.RaiseEvent();
}
else
{
Console.WriteLine("Error");
}
}
}
using System;
using System.Text;
using System.Data; namespace Class1
{
//定义事件引发时,需要传的参数
class NewMailEventArgs:EventArgs
{
private readonly string m_from;
private readonly string m_to;
private readonly string m_subject;
public NewMailEventArgs(string from, string to, string subject)
{
m_from = from;
m_to = to;
m_subject = subject;
}
public string From
{
get{return m_from;}
}
public string To
{
get{return m_to;}
}
public string Subject
{
get{return m_subject;}
} } //事件所用的委托(链表)
delegate void NewMailEventHandler(object sender, NewMailEventArgs e); //提供事件的类
class MailManager
{
public event NewMailEventHandler NewMail;
//通知已订阅事件的对象
protected virtual void OnNewMail(NewMailEventArgs e)
{
NewMailEventHandler temp = NewMail; //MulticastDelegate一个委托链表
//通知所有已订阅事件的对象
if(temp != null)
temp(this,e); //通过事件NewMail(一种特殊的委托)逐一回调客户端的方法 }
//提供一个方法,引发事件
public void SimulateNewMail(string from, string to, string subject)
{
NewMailEventArgs e = new NewMailEventArgs(from,to,subject);
OnNewMail(e);
}
} //使用事件
class Fax
{
public Fax(MailManager mm)
{
//Subscribe
mm.NewMail += new NewMailEventHandler(Fax_NewMail);
}
private void Fax_NewMail(object sender, NewMailEventArgs e)
{
Console.WriteLine("Message arrived at Fax...");
Console.WriteLine("From={0}, To={1}, Subject='{2}'",e.From,e.To,e.Subject);
}
public void Unregister(MailManager mm)
{
mm.NewMail -= new NewMailEventHandler(Fax_NewMail);
}
}
class Print
{
public Print(MailManager mm)
{
//Subscribe ,在mm.NewMail的委托链表中加入Print_NewMail方法
mm.NewMail += new NewMailEventHandler(Print_NewMail);
}
private void Print_NewMail(object sender, NewMailEventArgs e)
{
Console.WriteLine("Message arrived at Print...");
Console.WriteLine("From={0}, To={1}, Subject='{2}'",e.From,e.To,e.Subject);
}
public void Unregister(MailManager mm)
{
mm.NewMail -= new NewMailEventHandler(Print_NewMail);
}
} class ExcelProgram
{
[STAThread]
static void Main(string[] args)
{
MailManager mm = new MailManager();
if(true)
{
Fax fax = new Fax(mm);
Print prt = new Print(mm);
} mm.SimulateNewMail("Anco","Jerry","Event test");
Console.ReadLine();
}
}
}
ref和out的区别在C# 中,既可以通过值也可以通过引用传递参数。通过引用传递参数允许函数成员更改参数的值,并保持该更改。若要通过引用传递参数, 可使用ref或out关键字。ref和out这两个关键字都能够提供相似的功效,其作用也很像C中的指针变量。它们的区别是:
1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化。
2、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字。以满足匹配。
3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。
注:在C#中,方法的参数传递有四种类型:传值(by value),传址(by reference),输出参数(by output),数组参数(by array)。传值参数无需额外的修饰符,传址参数需要修饰符ref,输出参数需要修饰符out,数组参数需要修饰符params。传值参数在方法调用过程中如果改变了参数的值,那么传入方法的参数在方法调用完成以后并不因此而改变,而是保留原来传入时的值。传址参数恰恰相反,如果方法调用过程改变了参数的值,那么传入方法的参数在调用完成以后也随之改变。实际上从名称上我们可以清楚地看出两者的含义--传值参数传递的是调用参数的一份拷贝,而传址参数传递的是调用参数的内存地址,该参数在方法内外指向的是同一个存储位置。
方法参数上的 ref 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。ref 参数的值被传递到 ref 参数。
传递到 ref 参数的参数必须最先初始化。将此方法与 out 参数相比,后者的参数在传递到 out 参数之前不必显式初始化。
属性不是变量,不能作为 ref 参数传递。
如果两种方法的声明仅在它们对 ref 的使用方面不同,则将出现重载。但是,无法定义仅在 ref 和 out 方面不同的重载。
out
方法参数上的 out 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
当希望方法返回多个值时,声明 out 方法非常有用。使用 out 参数的方法仍然可以返回一个值。一个方法可以有一个以上的 out 参数。
若要使用 out 参数,必须将参数作为 out 参数显式传递到方法。out 参数的值不会传递到 out 参数。
不必初始化作为 out 参数传递的变量。然而,必须在方法返回之前为 out 参数赋值。
属性不是变量,不能作为 out 参数传递。
Delegate(委托与事件)的更多相关文章
- [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)
原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...
- 第一章、C#委托和事件(Delegate、Event、EventHandler、EventArgs)
第一章.C#委托和事件(Delegate.Event.EventHandler.EventArgs) 分类: 学习笔记-C#网络编程2012-12-08 14:10 7417人阅读 评论(3) 收藏 ...
- 委托和事件[delegate and event]_C#
委托和事件: 1. 委托:一个能够表示方法的数据类型:它将方法作为对象封装起来,允许在运行时间接地绑定一个方法调用. 2. 声明委托数据类型: public delegate bool Greate ...
- 转载: jQuery事件委托( bind() \ live() \ delegate()) [委托 和 绑定的故事]
转载:http://blog.csdn.net/zc2087/article/details/7287429 随着DOM结构的复杂化和Ajax等动态脚本技术的运用,事件委托自然浮出了水面.jQuery ...
- C# Note2:委托(delegate) & Lambda表达式 & 事件(event)
前言 本文主要讲述委托和Lambda表达式的基础知识,以及如何通过Lambda表达式实现委托调用,并阐述.NET如何将委托用作实现事件的方式. 参考:C#高级编程 1.什么是委托(delegate)? ...
- 委托与事件--delegate&&event
委托 访问修饰符 delegate 返回值 委托名(参数); public delegate void NoReturnNoPara(); public void NoReturnNoParaMeth ...
- .NET面试题系列[7] - 委托与事件
委托和事件 委托在C#中具有无比重要的地位. C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括但不限于)winform,wpf中的各种事件都有着委托的身影.C#中如果没有了事件,那 ...
- .NET基础拾遗(4)委托、事件、反射与特性
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- [转载]C#深入分析委托与事件
原文出处: 作者:风尘浪子 原文链接:http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html 同类链接:http://www.c ...
随机推荐
- [转] - hadoop中使用lzo的压缩
在hadoop中使用lzo的压缩算法可以减小数据的大小和数据的磁盘读写时间,不仅如此,lzo是基于block分块的,这样他就允许数据被分解成chunk,并行的被hadoop处理.这样的特点,就可以让l ...
- TestStand与LabVIEW UI 交互
交互起因 客户觉得TestStand界面复杂,希望一个简单的界面即可进行序列执行,采用LabVIEW调用TestStand引擎可实现快速设计,将TestStand拆解到LabVIEW.然而,这样做需要 ...
- 运行在VMware上的Linux虚拟机如何使用NAT模式连接物理机的外部网络
在VMware Workstation中,默认有3个虚拟交换机,分别是VMnet0(使用桥接网络).VMnet1(仅主机网络)和VMnet8(NAT网络). 首先说一下为什么要用NAT模式,如果你的物 ...
- iOS App TransportSecurity has blocked a cleartext HTTP (http://) resource load since it isinsecure. Temporary exceptions can be configured via your app's Info.plistfile
“App TransportSecurity has blocked a cleartext HTTP (http://) resource load since it isinsecure. Tem ...
- mysql批量替换指定字符串
将字段title中的abc替换为123 UPDATE `table1` SET `title` = replace(title, 'abc', '123') WHERE `typeid` =18;
- SpringBoot项目部署与服务配置
spring Boot 其默认是集成web容器的,启动方式由像普通Java程序一样,main函数入口启动.其内置Tomcat容器或Jetty容器,具体由配置来决定(默认Tomcat).当然你也可以将项 ...
- Unity学习疑问记录之layer问题
在Sprite Render中有个Sorting Layer,这里可以建层,而Inspector窗口中也有个layer,也可以新建层,这2者有什么不一样呢? layer主要通过光线投射来选择性地忽略碰 ...
- IOS第一天
第一天(hello world) 1>UIView所有的控件都继承UIView,倒位置,宽度和高度..UIButton UILable 2>UIViewController .h 是声明属 ...
- 【iCore3 双核心板】例程九:ADC实验——电源监控
实验指导书及代码包下载: http://pan.baidu.com/s/1o7wSEO6 iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...
- NEC学习 ---- 模块 -水平文字链接列表
HTML代码: <div class="container"> <div class="m-list1"> <ul class=& ...