一、什么是委托?
委托的本质 是一个类型安全的对象,它指向程序中另一个以后会被调用的方法。可以将方法作为参数传递,我个人理解,就像是点外卖,委托卖家来做,只需要说的口味和要求(委托调用时需要的参数),具体谁来做,怎么做,不需要去关心,只需要得到外卖小哥送来的东西(调用委托返回的结果);委托可以用于解耦,线程之间通信以及实现回调函数;
二、委托的使用
C#中使用delegate关键字创建委托,编译器在执行时会创建一个派生自System.MulticastDelegate 的类;此类继承于delegate基类,使其继承类可以访问包含由委托对象维护的方法地址的列表以及一些调用列表的附加方法;委托既可以指向静态方法,也可以指向实例方法;参考下面示例:
例:
public delegate int calc(int x,int y); //创建一个委托,指向传入两个参数并返回一个参数的方法
class Mathcalc
{
//委托指向的静态方法
public static int Add(int x, int y)
{
return x + y;
}
//委托指向的实例方法
public int Subtract(int x, int y)
{
return x - y;
}
}
static void Main(string[] args)
{
//创建一个Mathcalc实例
Mathcalc math = new Mathcalc();
//创建clac委托实例,并指向Mathcalc.Add()的静态方法
//也可以使用重载符号=直接指向方法;
//calc c = Mathcalc.Add;
calc c = new calc(Mathcalc.Add);
//使用委托对象调用方法
Console.WriteLine("{0}+{1}={2}", 20, 10, c(20, 10));
//指向实例方法
calc c1 = math.Subtract;
Console.WriteLine("{0}-{1}={2}", 20, 10, c1(20, 10));
}
结果:
20+10=30
20-10=10
Press any key to continue . . .
委托支持多路广播,一个委托对象可以添加多个方法,只需用+=重载操作符,也可以使用-=操作符将方法从调用列表中移除;委托对象调用一次,可以执行所有指向的方法,前提是指向的方法必须是无返回值的,当调用列表中是多个有返回值的方法时,只会执行最后一个,参考以下示例:
例:
//定义了有返回值和无返回值带两个参数的两个委托;
public delegate void calc1(int x,int y);
public delegate int calc2(int x, int y);
class Mathcalc
{
//无返回值的方法
public static void Add1(int x, int y)
{
Console.WriteLine("{0}+{1}={2}", x, y, x + y);
}
public void Subtract1(int x, int y)
{
Console.WriteLine("{0}+{1}={2}", x, y, x - y);
}
//有返回值的方法
public static int Add2(int x, int y)
{
return x + y;
}
public int Subtract2(int x, int y)
{
return x - y;
}
}
static void Main(string[] args)
{
Mathcalc math = new Mathcalc();
calc1 c1 = Mathcalc.Add1;
//用+=重载符将方法加入调用列表
c1 += Mathcalc.Add1;
c1 += math.Subtract1;
c1-= Mathcalc.Add1; //用-=移除一个方法
c1(20,10);
Console.WriteLine("\n\n--------------------\n\n");
calc2 c2 = Mathcalc.Add2;
c2 += math.Subtract2;
Console.WriteLine("result:"+c2(20,10));
}
结果:
20+10=30
20+10=10
--------------------
result:10
三、泛型委托Action<>和Func<>
C#中可以定义泛型委托。.net框架中也内置了两种泛型委托,大部分情况下,我们无需自己创建委托;Action<>是指向无返回值的方法的泛型委托,最多可以支持16个参数;Func<>是一个指向有返回值的方法的泛型委托,同样最多支持16个参数;关于内置泛型委托的使用,参考以下示例:
例:
//获取一个整数的n次幂
static void Print(long x,int n)
{
long temp = x;
for (int i = 1; i < n; i++)
x *= temp;
Console.WriteLine("{0}^{1}={2}", temp, n, x);
}
//判断一个正整数是否是质数
static bool isPrime(int x)
{
bool b = false;
if (x <= 1)
return b;
else {
for (int i = 2; i * i < x; i++)
{
if (x % i == 0)
{ b = true; break; }
}
return b;
}
}
static void Main(string[] args)
{
int temp=0;
//使用Func泛型委托,并指向返回bool类型并带有一个int类型的isPrime()方法;
Func<int, bool> func = isPrime;
//使用Action泛型委托,并指向无返回值带有两个int类型的Print()方法;
Action<long, int> action = Print;
Console.WriteLine("请输入一个正整数:");
temp = int.Parse(Console.ReadLine());
//使用创建委托对象调用参数
if (func(temp))
Console.WriteLine("{0}是一个合数",temp);
else
Console.WriteLine("{0}是一个质数",temp);
//使用创建委托对象调用参数
action(2,10);
}
结果:
请输入一个正整数:
2838921
2838921是一个合数
2^10=1024
四、泛型委托在LINQ函数中的实际应用
以上例子是为了演示泛型委托的使用方式,为了使用而使用,无法看出泛型委托实际应用;而在.net中内置了很多LINQ函数中,对泛型委托有着大量的应用,下面使用扩展方法和泛型委托实现LINQ函数中的where()功能,参考以下示例:
例:
//定义一个泛型接口IEnumerable<T>的扩展类
static class MyExtensions
{
//传入一个返回bool类型的泛型委托
public static IEnumerable<T> Filter<T>(this IEnumerable<T> Enmerable,Func<T,bool> func)
{
//返回所有满足条件的值
foreach (var item in Enmerable)
{
if (func(item))
yield return item;
}
}
}
//定义一个产品类
class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public string category { get; set; }
}
static void Main(string[] args)
{
//测试数据
int[] array = new int [] { 1,2,23,24,6,2,3,45,3};
List<Product> Products = new List<Product>() {
new Product { Id=1,category="电子产品",ProductName="IPhone xs"},
new Product { Id=2,category="电子产品",ProductName="Ipad"},
new Product { Id=3,category="家用游戏机",ProductName="PS4 Pro"},
new Product { Id=4,category="家用游戏机",ProductName="Switch"},
new Product { Id=5,category="家具",ProductName="沙发"},
new Product { Id=6,category="日常用品",ProductName="牙刷"},
};
//使用lambda表达式传入调用方法
var list1 = array.Filter(i=>i>5);
foreach (var item in list1)
{
Console.WriteLine(item);
}
Console.WriteLine("\n\n------------\n\n");
var list2 = Products.Filter(i=>i.category=="家用游戏机" || i.ProductName=="Ipad");
foreach (var item in list2)
{
Console.WriteLine("{0}:{1}",item.category,item.ProductName);
}
}
结果:
23
24
6
45
------------
电子产品:Ipad
家用游戏机:PS4 Pro
家用游戏机:Switch