泛型委托:由于类型参数决定泛型委托能够接收什么样的方法;所以相较非泛型委托更加灵活。
声明自定义的泛型委托
public delegate R ReportResult<T, R>(T pams);
定义泛型委托变量
/// <summary>
/// 泛型委托的构造类型:需要一个形参为int类型、返回值类型为bool类型的方法对其进行初始化
/// </summary>
private static ReportResult<int, bool> _isOlderThanHim;
/// <summary>
/// 泛型委托的构造类型:需要一个形参为string类型、返回值类型为int类型的方法对齐进行初始化
/// </summary>
private static ReportResult<string, int> _caculatorAge;
赋值并调用泛型委托变量
class Program
{
/// <summary>
/// 泛型委托的构造类型:需要一个形参为int类型、返回值类型为bool类型的方法对其进行初始化
/// </summary>
private static ReportResult<int, bool> _isOlderThanHim;
/// <summary>
/// 泛型委托的构造类型:需要一个形参为string类型、返回值类型为int类型的方法对齐进行初始化
/// </summary>
private static ReportResult<string, int> _caculatorAge;
static void Main(string[] args)
{
_isOlderThanHim = new Student().IsAdult;
var ret = _isOlderThanHim.Invoke(14);
Console.WriteLine(ret);
_caculatorAge=new Student().AfterYears;
var age= _caculatorAge.Invoke("5");
Console.WriteLine(age);
Console.ReadLine();
}
}
/// <summary>
/// 定义一种操作:根据传入的实参返回相应的结果
/// </summary>
/// <param name="pams"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="R"></typeparam>
public delegate R ReportResult<T, R>(T pams);
class Student
{
private int StudentAge { get; set; } = 15;
/// <summary>
/// 返回学生的年龄与传入的数值的比较结果
/// </summary>
/// <param name="age"></param>
/// <returns></returns>
public bool IsAdult(int age)
{
var ret = age >= StudentAge;
return ret;
}
/// <summary>
/// 返回学生year年后的年龄
/// </summary>
/// <param name="years"></param>
/// <returns></returns>
public int AfterYears(string years)
{
try
{
return StudentAge + Convert.ToInt32(years);
}
catch (Exception ex)
{
Console.WriteLine(ex);
return StudentAge;
}
}
}
运行结果:
False
20
分析:如果想要调用Student类中的两个方法一个只声明一个非泛型委托是不够的。这里便体现出了泛型委托的优点。
.NET预定义的泛型委托类型
.NET给我们预定义了很多泛型委托,日常编码工作中使用这些类型的泛型委托基本就已足够,下面我们只介绍三个常用的预定义的泛型委托。
第一个:Predicate
使用场景:当我们需要判断数据是否满足某些条件时,就采用Predicate
使用这个泛型委托,我们就可以调用Student类中返回值类型为bool的方法了
class Program
{
private static ReportResult<int, bool> _isOlderThanHim;
private static Predicate<int> _isOlder;
static void Main(string[] args)
{
_isOlderThanHim = new Student().IsAdult;
var ret = _isOlderThanHim.Invoke(14);
Console.WriteLine(ret);
_isOlder = new Student().IsAdult;
var retWithPredicate = _isOlder.Invoke(18);
Console.WriteLine(retWithPredicate);
Console.ReadLine();
}
}
/*
运行结果:
False
True
*/
第二个:Func<T,TResult>
使用场景:当我们对数据进行操作后、还希望将处理结果返回时,就采用Func<T,TResult>委托。
由于Func拥有两个类型参数,它接收的方法要比Predicate
class Program
{
private static ReportResult<int, bool> _isOlderThanHim;
private static ReportResult<string, int> _caculatorAge;
private static Predicate<int> _isOlder;
private static Func<string, int> _caculatorAgeFunc;
static void Main(string[] args)
{
_isOlderThanHim = new Student().IsAdult;
var ret = _isOlderThanHim.Invoke(14);
Console.WriteLine(ret);
_isOlder = new Student().IsAdult;
var retWithPredicate = _isOlder.Invoke(18);
Console.WriteLine(retWithPredicate);
_caculatorAge = new Student().AfterYears;
var age = _caculatorAge.Invoke("5");
Console.WriteLine(age);
_caculatorAgeFunc = new Student().AfterYears;
var ageWithFunc = _caculatorAgeFunc.Invoke("7");
Console.WriteLine(ageWithFunc);
Console.ReadLine();
}
}
/*
输出:
20
22
*/
第三个:Action
使用场景:当我们仅仅需要用数据执行一些操作,并不希望得到返回值时,使用Action
我们给Studnet类中添加一个拥有一个形参,返回值为void的方法
class Student
{
private int StudentAge { get; set; } = 15;
/// <summary>
/// 打印出学生year年后的年龄
/// </summary>
/// <param name="year"></param>
private void ShowAfterYear(string year)
{
try
{
Console.WriteLine(StudentAge + Convert.ToInt32(year));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
下面演示如何使用Action
class Program
{
private static Action<string> _printAgeAciton;
static void Main(string[] args)
{
_printAgeAciton = new Student().ShowAfterYear;
_printAgeAciton.Invoke("12");
Console.ReadLine();
}
}
/*
运行结果:
27
*/
C#的LINQ特性中,很多地方都使用了泛型委托
下面展示一下Linq中用到的泛型委托:
namespace GenericDemo
{
class Program
{
static void Main(string[] args)
{
List<Student> list = new List<Student>();
list.Add(new Student() {StudentName = "唐三", StudentAge = 17, ClassGroup = "史莱克学院"});
list.Add(new Student() {StudentName = "风笑天", StudentAge = 18, ClassGroup = "神风学院"});
list.Add(new Student() {StudentName = "邪月", StudentAge = 22, ClassGroup = "武魂殿"});
list.Add(new Student() {StudentName = "胡烈娜", StudentAge = 20, ClassGroup = "武魂殿"});
list.Add(new Student() {StudentName = "朱竹青", StudentAge = 19, ClassGroup = "史莱克学院"});
list.Add(new Student() {StudentName = "焱", StudentAge = 19, ClassGroup = "武魂殿"});
Console.WriteLine("遍历所有人员");
list.ForEach(new Action<Student>(PrintStudentInfo));
Console.WriteLine("=================");
Console.WriteLine("按照班级分组");
var grouList = list.GroupBy(new Func<Student, string>(GetGroup));
foreach (IGrouping<string, Student> grouping in grouList)
{
foreach (Student student in grouping)
{
Console.WriteLine(student);
}
}
Console.Write("队伍中有未成年么?");
var isHasNotAdult = list.Any(new Func<Student, bool>(IsNoAdult));
Console.WriteLine(isHasNotAdult);
Console.WriteLine("=================");
Console.WriteLine("找出未成年的人员");
var isNoAdult = list.Where(new Func<Student, bool>(IsNoAdult));
foreach (Student student in isNoAdult)
{
Console.WriteLine(student);
}
Console.ReadLine();
}
private static void PrintStudentInfo(Student stu)
{
Console.WriteLine(stu);
}
private static bool IsNoAdult(Student stu)
{
return stu.StudentAge < 18;
}
private static string GetGroup(Student stu)
{
return stu.ClassGroup;
}
}
class Student
{
public string StudentName { get; set; }
public int StudentAge { get; set; }
public string ClassGroup { get; set; }
public override string ToString()
{
return $"{this.ClassGroup}:{this.StudentName},{this.StudentAge}";
}
}
}
/*
运行结果:
遍历所有人员
史莱克学院:唐三,17
神风学院:风笑天,18
武魂殿:邪月,22
武魂殿:胡烈娜,20
史莱克学院:朱竹青,19
武魂殿:焱,19
=================
按照班级分组
史莱克学院:唐三,17
史莱克学院:朱竹青,19
神风学院:风笑天,18
武魂殿:邪月,22
武魂殿:胡烈娜,20
武魂殿:焱,19
队伍中有未成年么?True
=================
找出未成年的人员
史莱克学院:唐三,17
*/
上面的每个Linq方法都接收一个泛型委托作为形参;通过上面的代码我们可以明显感受到使用泛型委托能够给我们带来很大的方便。
以上便是对泛型委托的总结,记录下来以便以后查阅。