委托
委托是C#编程语言新提出的面向对象概念。委托其实就是把程序的某些功能交给其他地方的代码来实现。因为有些时候程序的流程并不确定,所以不自己实现,这些不确定的调用只能通过其他的外部程序来确定。
这时候我们就需要委托,在外部程序中指定应该调用的方法来完成这个功能。委托类似于C++中的函数指针,当并不完全相同。因为委托概念是面向对象的,所以委托必须封装在类内部。委托能够对应多个方法,可以在程序运行时动态加减。
1. 委托的定义
C#编程语言要求开发人员非常熟悉委托,并且能够根据代码实现的场景,声明和使用委托。委托常用的场合大致分为以下4个方面。
- 一个类中需要调用不确定的方法时
- 在类中声明事件时
- 在类中调用不应在类中实现的方法时
- 在接口中调用其他接口的方法时
面向对象编程,需要使用类将事物封装成相对独立的单元,减少了外部程序对类所包含数据的干扰,但是事物与事物之间总是由各种各样的关系,所以封装在一定程度上为编程带来了麻烦,委托就是为了处理此类的问题。
使用委托的好处是当外部条件改变时,不用修改每个调用类的定义。委托降低了类与类之间互相调用的耦合程度。
委托的定义包括三个方面,首先使用delegate关键字表示将要声明一个委托,接着是委托的数据类型,最后是委托的名称和参数列表。
public delegate decimal Price Adjustment(Order AdjustmentOrder);
委托代码案例:
using System;
namespace cn.wellswang
{
public class Order
{
public string CoffeeName { get; set; }
public int AreaID { get; set; }
public decimal BasePrice { get; set; }
// 声明价格调整的委托
public delegate decimal PriceAdjustmentDelegate(Order AdjustmentOrder);
// Order类的委托实例变量
public PriceAdjustmentDelegate PriceAdjustment;
public decimal FinalPrice
{
get
{
return BasePrice + PriceAdjustment(this);
}
}
}
public class Adjustment
{
private decimal Addition = 0;
public decimal BikePrice(Order AdjustmentOrder)
{
Addition += 5m;
return Addition;
}
public decimal CarPrice(Order AdjustmentOrder)
{
Addition += 10m;
return Addition;
}
public decimal Foam(Order AdjustmentOrder)
{
Addition += 0.5m;
return Addition;
}
public decimal Heat(Order AdjustmentOrder)
{
Addition += 1m;
return Addition;
}
}
public class Sale
{
public Order SaleOrder { get; set; }
public Adjustment SaleAdjsutment { get; set; }
public void DoSale()
{
switch (SaleOrder.AreaID)
{
case 1:
SaleOrder.PriceAdjustment +=
new Order.PriceAdjustmentDelegate
(SaleAdjsutment.BikePrice);
SaleOrder.PriceAdjustment +=
new Order.PriceAdjustmentDelegate
(SaleAdjsutment.Foam);
break;
case 2:
SaleOrder.PriceAdjustment +=
new Order.PriceAdjustmentDelegate
(SaleAdjsutment.CarPrice);
SaleOrder.PriceAdjustment +=
new Order.PriceAdjustmentDelegate
(SaleAdjsutment.Foam);
break;
case 3:
SaleOrder.PriceAdjustment +=
new Order.PriceAdjustmentDelegate
(SaleAdjsutment.CarPrice);
SaleOrder.PriceAdjustment +=
new Order.PriceAdjustmentDelegate
(SaleAdjsutment.Heat);
break;
}
}
}
public class Test
{
public static void Main(string[] args)
{
Sale MySale = new Sale();
MySale.SaleOrder = new Order();
MySale.SaleOrder.BasePrice = 30;
MySale.SaleOrder.AreaID = 3;
MySale.SaleAdjsutment = new Adjustment();
MySale.DoSale();
Console.Write("最终价格:" + MySale.SaleOrder.FinalPrice.ToString()); // 41
}
}
}
2. 事件委托
在C#编程语言中,事件必须声明为委托类型,没有声明方法的事件是没有意义的。事件,相当于委托实例变量,说不同的是声明事件的代码中多了一个event关键字。
事件与委托类的实例变量很相似,在这个实例变量中可以添加、移除符合委托声明的方法。这也意味着可以用多种方法处理一个事件。最为常见的是一个事件对应一个处理方法。
using System;
namespace cn.wellswang
{
public class LoginEvent : EventArgs
{
public string UserName { get; set; }
public string PassWord { get; set; }
public LoginEvent(string username, string password)
{
UserName = username;
PassWord = password;
}
}
public class Login
{
public string UserName { get; set; }
public string PassWord { get; set; }
public delegate void LoginHandler(LoginEvent e);
public event LoginHandler OnLogin;
public void ActiveLogin()
{
OnLogin(LoginEvent(UserName, PassWord));
}
}
public class LoginPage
{
private Login UserLogin = new Login();
private bool IfLogined = false;
public string URLToShow;
public void DoLogin()
{
UserLogin.UserName = "Wells";
UserLogin.PassWord = "001005";
UserLogin.OnLogin += new Login.LoginHandler(VerifyUser);
UserLogin.OnLogin += new Login.LoginHandler(ShowOrders);
UserLogin.ActiveLogin();
}
void VerifyUser(LoginEvent e)
{
if (e.UserName == "Wells" && e.PassWord == "001005")
{
IfLogined = true;
}
}
void ShowOrders(LoginEvent e)
{
if(IfLogined)
{
URLToShow = "报销单审核情况.aspx";
}
}
}
}
事件本身包含一个调用列表,在事件产生时,按照列表的顺序执行指定的方法。
事件委托和一般委托是很相似的,不同点就在于这个调用列表,事件委托的调用列表只能通过"+=“运算符和”-=“运算符来改变,而一般委托可以使用”="运算符,直接使用一个调用列表给委托赋值。事件委托的这种赋值方式,在一定程度上,避免了事件调用列表的方法被某段程序代码完全替换。