本章内容:
什么是委托?
声明委托对象?
创建委托对象?
赋值委托?
组合委托?
为委托增加方法?
从委托移除方法?
调用委托?
委托的实例?
调用带返回值的委托?
调用带引用的委托?
匿名方法?
Lambda表达式?
什么是委托?
委托:有相同签名和返回值类型的有序方法列表
(1) 方法的列表称为调用列表
(2) 当委托被调用时,它调用列表中的每一个方法
声明委托类型
委托是类型,就好像类是类型一样,所以必须在创建变量之前声明,并且不需要在类内部声明。(以delegate关键词开头,没有方法的主体)
例如:
delegate void MyDel(int x);
delegate 关键词
void 返回类型
MyDel 委托类型名
MyDel(int x) 签名
返回类型和签名指定了委托接受方法的形式
例如如上声明的委托:只会接受不返回值,并且有单个int参数的方法。
创建委托对象
委托变量的声明:MyDel delVar;
委托是引用类型,因此有引用和对象,因此有两种方式:
1、 使用带new运算符的对象创建表达式
2、 使用快捷语法,由方法的说明符构成
delVar=new MyDel(myInstObj.MyM1); //myInstObj.MyM1可以是实例方法或者静态方法
或者
delVar= myInstObj.MyM1;
赋值委托
由于委托是引用类型,因此可以通过给它赋值来改变包含在委托变量中的引用
例如:
MyDel delVar;
delVar= myInstObj.MyM1;
delVar=SClass.OtherM2;
组合委托
委托可以使用额外的运算符来“组合”,并最终会创建一个新的委托
例如:如下代码创建了3个委托,第三个委托由前两个委托组合。
MyDel delA= myInstObj.MyM1;
MyDel delB=SClass.OtherM2;
MyDel delC=delA+delB;
为委托增加方法
我们可以通过使用+=运算符为委托增加方法或者另一个委托。
MyDel delVar=inst.MyM1;//创建并初始化
delVar += SC.M3; //增加方法
delVar += X.Act; //增加方法
当使用 += 运算符时,实际发生的是创建了一个新的委托。其调用列表时左边的委托加上右边方法的组合。
从委托移除方法
我们可以使用 -= 运算符从委托移除方法
delVar -= X.Act; //从委托上移除X.Act方法
与为委托添加方法一样,其实是创建了一个新的委托。
调用委托
可以像调用方法一样简单的调用委托。调用委托中的参数将会用于调用列表中的每一个方法。
例如:
delegate void MyDel(int x);
MyDel delVar=inst.MyM1;
delVar += S.m3;
delVal(55); //调用委托
delVar委托接受一个int型输入值,调用委托就会使用相同的参数值(55)去调用它的调用列表中的每一个成员。
一个方法可以在调用列表中出现多次。
委托示例
delegate void PrintDelegate();//声明委托
class TestDelegate
{
int IntValue = 5;
public void Print1()
{
Console.WriteLine("Print1---instance");
}
public static void Print2()
{
Console.WriteLine("Print2---static");
}
}
class Program
{
static void Main(string[] args)
{
PrintDelegate myDel = new PrintDelegate(TestDelegate.Print2);
TestDelegate t = new TestDelegate();
myDel += t.Print1;
myDel();//调用委托
}
}
调用带返回值的委托
如果委托有返回值并且在调用列表中有一个以上的方法,会发生下列情况:
1、 调用列表中最后一个方法返回的值就是委托调用返回的值
2、 调用列表中所有其他方法的返回值都会被忽略
delegate int PrintAdd();//声明委托
class TestDelegate
{
int IntValue = 5;
public int Add2()
{
IntValue += 2;
return IntValue;
}
public int Add3()
{
IntValue += 3;
return IntValue;
}
}
class Program
{
static void Main(string[] args)
{
TestDelegate t = new TestDelegate();
PrintAdd p1;
p1 = t.Add2;
p1 += t.Add3;
p1 += t.Add2;
if (null != p1)
{
Console.WriteLine("IntValue={0}", p1());
}
else
{
Console.WriteLine("delegate is empty");
}
Console.Read();
}
}
这段代码产生输出:IntValue=12
调用带引用参数的委托
如果委托有引用参数,参数值会根据调用列表中的一个或多个方法的返回值而改变;
delegate void MyDel(ref int x);
class MyClass {
public void Add2(ref int x){ x+=2;}
public void Add3(ref int x){ x +=3;}
static void Main(){
MyClass mc=new MyClass();
MyDel mydel=mc.Add2;
mydel += mc.Add3;
mydel += mc.Add2;
int x=5;
mydel(ref x);
Console.WriteLine(“Value:{0}”,x);
}
}
这段代码输出 Value:12
匿名方法
如果方法只会被使用一次,可以使用匿名方法
匿名方法:是在初始化委托时内联声明的方法
Class program{ Public static int Add20(int x) { return x+20; } delegate int OtherDel(int param); Static void Main(){ OtherDel del=Add20; Console.WriteLine(del(5)); Console.WriteLine(del(6)); } } | Class program{
delegate int OtherDel(int param); Static void Main(){ OtherDel del=delegate(int x){ return x+20; } Console.WriteLine(del(5)); Console.WriteLine(del(6)); } } |
如上演示了同一个类的两个版本。
左边的版本声明并使用了一个名称为Add20的方法。
右边的版本使用了匿名方法代替,左边灰色底的代码和右边灰色底的代码是等价的。
匿名方法的语法:
delegate (parameters){ ImplementationCode}
delegate 为关键词
parameters 为参数列表,如果语句块没有任何参数,则可以省略
ImplementationCode 包含匿名方法的代码
Lambda表达式
为了简化匿名方法的语法,C#3.0引入了lambda表达式,希望使用lambda表达式来替代匿名方法。
通过如下步骤把匿名方法转换为lambda表达式;
1、 删除delegate 关键字
2、 在参数列表和匿名方法主体之间放lambda运算符=>。Lambda运算符读作“goes to”
例如:
MyDel del=delegate(int x){ return x+1;}; //匿名表达式
MyDel le1= (intx)=>{ return x +1;};//Lambda表达式
MyDel le2= (x) =>{return x+1;};
MyDel le3= x=>{return x+1;};
MyDel le4= x=> x+1;
使用lambda表达式,如果没有参数,必须使用一组空的圆括号。