泛型委托Action
Action的定义
在.Net2.0里面,Action只有一个定义
public delegate void Action(T arg);
定义一个普通的委托格式是:
public delegate void PuTongWeiTuo(int a, int b);或者
public delegate string PuTongWeiTuo(int a, int b);
在.Net3.5及以上,Action有4种定义
public delegate void Action(T arg);
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
不同点是参数越来越多,相同点是,所有的Action都被定义为无返回值。Action的四种形式是:1参无返回、2参无返回、3参无返回、4参无返回。
当然了,虽然.NET2.0没有定义其他的Action但是可以手动定义。想定义几个就定义几个。因为在不同的namespace,即便是跟一定定义过的Action重复了,也是可以的。
①public delegate void Action<T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
②public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
③public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
④public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
⑤public delegate void Action<T1>(T1 arg1);
任何版本的.NET都可以这么定义。第一个定义了一个五参无返回且名字为Action的委托。后面四个将已经定义过的Action重新定义了一遍.
Action的其中一种使用场景
我本人在项目开发中经常遇到一些通过服务器查询数据的情况。在实际项目开发中,模块化思想需要将查询模块和界面是分开。所以查询模块需要提供接口给界面使用,使得界面能够利用查询模块提供的接口进行数据查询。
在上面描述的场景中,两个模块的交互就可以使用委托的方法来进行,而且这种方法要比其他方法的代码可读性更强,代码更容易阅读,一目了然。
场景实例
假设界面有如下需求: 从服务器获取某一年度天气状况为良好的所有日期(类型为DateTime)。
从需求中可以确认:
查询的条件是:“年份”,“天气状况”。
查询的结果是:一组时间
那么我们可以定义如下委托:
/// <summary>
/// 委托:获取年份为year的,空气质量为airCondition的所有日期。
/// </summary>
/// <param name="year">年份</param>
/// <param name="airCondition">true表示空气质量良好</param>
/// <returns></returns>
public delegate List<DateTime> GetDateList(int year, bool airCondition);
但是这样定义的委托在使用过程中有一个缺陷。就是如果网络差的时候,委托会一直一直等待结果回来,会导致界面卡死。使用多线程的方法也行不通,因为后面很快就要使用到查询回来的这些日期,还是要等待结果。
可以加入回调的方法。
/// <summary>
/// 委托:获取年份为year的,空气质量为airCondition的所有日期。
/// </summary>
/// <param name="year">年份</param>
/// <param name="airCondition">true表示空气质量良好</param>
/// <param name="dateTimeResultListHandler">处理</param>
public delegate void GetDateList(int year, bool airCondition, Action<List<DateTime>> dateTimeResultListHandler);
在上面定义的委托的参数列表中还有一个委托Action,Action在上面说过,是一个有参无返回的函数。也就是说
Action<List> dateTimeResultListHandler
这个参数其实传过去的是一个没有返回值的函数,是仅有一个参数,且参数类型为List的函数。这个函数干嘛用呢。前两个参数分别是int year, bool airCondition这两个参数足够计算出结果List了。然后将计算出来的结果输入到dateTimeResultListHandler函数中,并且在执行函数dateTimeResultListHandler的过程中使用线程池技术。这样就不会阻塞主界面,主界面也不需要等待结果回来了。而是结果回来之后自行处理。
这种情况也可以使用事件,接口来完成。但是使用委托更加的方便,代码的可读性也更强。
可能有不少人并不知道“回调函数”中的“回调”是什么意思。在上面的例子中函数dateTimeResultListHandler并不第一时间执行,而是等目标函数返回结果之后来执行。这种方式就叫“回调”
结尾
重要的事情说三遍,Action是泛型委托,Action是泛型委托,Action是泛型委托。区别于很多自己定义的委托。比如我们前面自己定义的GetDateList。我们在使用GetDateList的时候直接GetDateList();或者就行了GetDateList.Invoke();但是使用泛型委托的时候还必须要指定类型。
定义和使用普通委托。
- 普通委托示例一:
定义:
public delegate DateTime GetDate(int year);
使用:
var ret = GetDate(2019);
或者var ret = GetDate.Invoke(2019);
定义和使用泛型委托。
- 泛型委托示例一:
static void Main(string[] args)
{
Action<string,string> BookAction = new Action<string,string>(Book);
BookAction("百年孤独","北京大书店");
}
public static void Book(string BookName,string ChangJia)
{
Console.WriteLine("我是买书的是:{0}来自{1}",BookName,ChangJia);
}
- 泛型委托示例二:
getDataDelegate(AlarmLevel.Level1, new Action<List<AlarmResult>>((resultList) => this.Invoke(new MethodInvoker(() =>
{
if (resultList.Count == 0) return;
foreach (AlarmResult result in resultList)
{
DataRow row = _dataTable.NewRow();
row["报警级别"] = result.AlarmLevel;
row["设备名称"] = result.DevName;
row["报警描述"] = result.AlarmInfo;
row["报警时间"] = result.AlarmTime;
row["报警次数"] = result.AlarmCount;
row["是否确认"] = result.IsConfirm;
this._dataTable.Rows.Add(row);
}
this.ultraGrid.Refresh();
this.BackColor = Color.Red;
}))));
getDataDelegate(AlarmLevel.Level1, (resultList) => this.Invoke(new MethodInvoker(() =>
{
if (resultList.Count == 0) return;
foreach (AlarmResult result in resultList)
{
DataRow row = _dataTable.NewRow();
row["报警级别"] = result.AlarmLevel;
row["设备名称"] = result.DevName;
row["报警描述"] = result.AlarmInfo;
row["报警时间"] = result.AlarmTime;
row["报警次数"] = result.AlarmCount;
row["是否确认"] = result.IsConfirm;
this._dataTable.Rows.Add(row);
}
this.ultraGrid.Refresh();
this.BackColor = Color.Red;
})));
还有个泛型委托Func,跟Action一样的。只不过它是有参有返回,大概,这个Action算是我日常项目中用于作为回调函数的最多的了