在C#中定义委托时要用关键字delegate ,名字自己起如:public delegate int BinaryOp(int x,int y);
当C#编译器处理委托类型时,它先自动产生一个派生自System.MulticastDelegate的密封类。这个类与它的基类System.Delegate一起为委托提供必要的基础设施,以维护以后将要调用的方法的列表。如我们可以通过ildasm.exe来查看BinaryOp委托,如下:
可见生成的BinaryOp类定义了3个公共方法:BeginEnvoke(); Invoke(),EndInvoke();其中Invoke()是核心方法;因为它被用来以同步方式调用委托对象维护的每个方法。这里的同步是指调用者必须等待调用完成才能继续执行。
下面我们举个最简单的委托代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 委托学习
{
public delegate int BinaryOp(int x,int y);
public class SimpleMath
{
public int Add(int x,int y)
{
return x + y;
}
public static int Subtract(int x, int y)
{
return x - y;
}
public void DisplayDelegateInfo(Delegate delObj)
{
foreach (Delegate d in delObj.GetInvocationList())
{
Console.WriteLine("Method name is :{0}",d.Method);
Console.WriteLine("Type name is :{0}",d.Target);
}
}
}
class Program
{
static void Main(string[] args)
{
SimpleMath m = new SimpleMath();
BinaryOp b = new BinaryOp(m.Add);
Console.WriteLine("10+10={0}",b(10,10));
Console.WriteLine("10+10={0}", b.Invoke(10, 10));
m.DisplayDelegateInfo(b);
Console.ReadKey();
}
}
}
运行结果:
下面我们来看下有关委托的实例:
有关概念:
1. 支持多路委托:就是一个委托上绑定多个与委托定义相匹配的方法具体看如下例子;
2. +=:就是向委托添加一个新的绑定方法;
3. -= :同+=,只是把一个方法从委托上注销掉;
4. 方法组转换:也就是当向注册函数添加委托变量时可以不写委托实例直接添加委托方法具体见实例代码;
5. 委托协变 :当一个委托要求返回一个自定义类类型的时候,有可能我们一个类是继承的父类,但委托中要求返回的是父类类型,那我们就可以不用定义两个委托只定义一个返回类型为父类的委托,用这个委托来调用返回子类的方法,只不过在调用时用强制类型转换下就可以了如下代码;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 委托中级
{
public class Car
{
//内部状态数据
public int CurrentSpeed { get; set; }
public int MaxSpeed { get;set;}
public string PetName{get;set;}
//汽车能用还是不能用
private bool carIsDead;
//类构造函数
public Car()
{
MaxSpeed = 100;
}
public Car(string name,int maxSp,int currSp)
{
CurrentSpeed = currSp;
MaxSpeed = maxSp;
PetName = name;
}
//定义委托类型
public delegate void CarEngineHander(string msgForCaller);
//定义每个委托类型的成员变量
private CarEngineHander listOfHanders;
//向调用者添加注册函数
//修改下使之支持多路广播,也就是把=变成+=
public void RegisterWithCarEngine(CarEngineHander methodToCall)
{
//+=操作符实际上转换为一个对静态Delegate.Combine()方法的调用;我们可以从CIL中发现。
listOfHanders += methodToCall;
}
//取消注册某方法
public void UnRegisterWithCarEngine(CarEngineHander methodToCall)
{
listOfHanders -= methodToCall;
}
public void Accelerate(int delta)
{
//如果汽车不能用,触发引爆事件
if (carIsDead)
{
if (listOfHanders != null)
listOfHanders("Sorry, this car is dead....");
}
else
{
CurrentSpeed += delta;
//快不能用了吗
if (10 == (MaxSpeed - CurrentSpeed) && listOfHanders != null)
{
listOfHanders("Careful buddy! Gonna blow!");
}
if (CurrentSpeed >= MaxSpeed)
carIsDead = true;
else
Console.WriteLine("CurrentSpeed is : {0}.", CurrentSpeed);
}
}
}
public class SportCar : Car
{
}
class Program
{
static void Main(string[] args)
{
#region 委托的注册与Un注册
Console.WriteLine("*****Delegate as event enablers*****");
Car c = new Car("宝马", 100, 10);
//还有个知识点就是方法组转换,也就是在注册事件中不引用如下的委托对象而是与其对应的方法如下 :
//c.RegisterWithCarEngine(OnCarEngineEvent);
c.RegisterWithCarEngine(new Car.CarEngineHander(OnCarEngineEvent));
Car.CarEngineHander handler = new Car.CarEngineHander(OnCarEngineEvent2);
c.RegisterWithCarEngine(handler);
//c.RegisterWithCarEngine(new Car.CarEngineHander(OnCarEngineEvent2));
Console.WriteLine("*****Speeding up*****");
for (int i = 0; i < 6; i++)
{
c.Accelerate(20);
//注销第二个处理程序
c.UnRegisterWithCarEngine(handler);
//Console.ReadLine();
}
Console.WriteLine("**** Delegate Convariance ****");
ObtainVehicleDelegate targetA = new ObtainVehicleDelegate(GetbasicCar);
Car car = targetA();
Console.WriteLine("Obtiond a {0}",car);
ObtainVehicleDelegate targetB = new ObtainVehicleDelegate(GetSportCar);
SportCar sportCar = (SportCar)targetB();
Console.WriteLine("Obtiond a {0}", sportCar);
Console.ReadKey();
}
public static void OnCarEngineEvent(string msg)
{
Console.WriteLine("\n****Message From Car Object****");
Console.WriteLine("==》{0}", msg);
Console.WriteLine("*********************************\n");
}
public static void OnCarEngineEvent2(string msg)
{
Console.WriteLine("==》:{0}", msg.ToUpper());
}
#endregion
#region 委托协变
public delegate Car ObtainVehicleDelegate();
public static Car GetbasicCar()
{
return new Car();
}
public static SportCar GetSportCar()
{
return new SportCar();
}
#endregion
}
}
运行结果如下:
下面再学习下 Generic Delegate吧
例如我们想定义一个委托类型来调用任何返回void并且接受单个参数的方法。如果这个参数可能会不同;我们就可以使用类型参数来构建简单的例子来帮助理解:
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Generic_Delegate
{
public class Program
{
public delegate void MyGenericDelegate<T>(T arg);
static void Main(string[] args)
{
Console.WriteLine("***** Generic Delegate *****");
//注册目标
MyGenericDelegate<string> strTarget = new MyGenericDelegate<string>(StringTaget);
strTarget("some String Data");
MyGenericDelegate<int> intTarget = new MyGenericDelegate<int>(IntTarget);
intTarget(9);
Console.ReadLine();
}
static void StringTaget(string arg)
{
Console.WriteLine("arg in uppercase is :{0}",arg.ToUpper());
}
static void IntTarget(int arg)
{
Console.WriteLine("++arg is {0}",++arg);
}
}
}
到这委托的学习就差不多了。