CLR之委托的揭秘(二)

时间:2022-12-05 11:59:21

杂谈

在开始真正的代码之前,分析一下上周的一些工作内容,发现自己在代码上还是有很多小毛病需要纠正和去更改的,首先之前一直疏于文档的整理,几乎很少去写文档,第二对于接口开发过程中缺少一定的严谨性,很多问题没有考虑清楚就已经代码敲完了,其实应该先针对接口去写一份接口说明文档,一方面提升自己的文档能力,另外一方面也通过文字整理自己的思路,还有就是程序开发中不能懒,因为懒已经出了很多问题,程序毕竟是严谨的,你忽能它,它也必然忽能你!

这是上周工作中的一些总结,接下来继续以CLR的角度分析委托,上一节说了委托的定义,委托链,还有匿名委托。接下来我们分析

泛型委托

其实我对于泛型委托之前也是完全一知半解,有一次在用Linq的时候,先用了Where有用了Find,我的本意是先筛选在查找,但实际上两者基本上是一回事,都是泛型委托,当然关于泛型委托不得不说的就是 Action<T> 泛型委托, Func<T, TResult>,两者是有区别的

Action<T> 泛型委托:封装一个方法,该方法只采用一个参数并且不返回值。可以使用此委托以参数形式传递方法,而不用显式声明自定义的委托。该方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能返回值。当然泛型委托不只是只能支持一个参数,它最多可以支持四个参数。

Func<T, TResult> 委托:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。同理,这里的泛型委托只是接受一个参数的委托,它最多同样支持四个参数。TResult:此委托封装的方法的返回值类型。

Action T

还记得上一篇文章中我们关于委托的定义和声明中,是如何要求的么?委托的安全性非常高,所以在声明委托时,要声明委托返回的类型和参数类型,但是在 Action<T> 上,我们不需要如此,接下来看一下普通声明和Action<T> 声明的委托有什么不同

        /*
泛型委托和普通委托的声明对比
1.不需要使用delegate关键字
2.Action只能使用返回值为void的方法,如果返回值具有对象类型则报错
*/
delegate void DisplayMessage(string message);
static void Main(string[] args)
{ DisplayMessage messageTarget;
messageTarget = ShowWindowsMessage;
messageTarget("Hello, World!"); Action<string> messageTarget1;
messageTarget1 = ShowWindowsMessage;
messageTarget1("泛型委托");
}
public static void ShowWindowsMessage(string s) {
Console.WriteLine(s);
}

我在注释里加入了一行解释:不需要使用delegate关键字,为什么 Action<T> 可以直接声明使用呢?这和其自身封装有关,下面代码就是其在系统中的封装,可以看出来,Action在元数据中就已经存在了public delegate void封装,明确了其使用的范围

  //
// 摘要:
// 封装一个方法,该方法只有一个参数并且不返回值。
//
// 参数:
// obj:
// 此委托封装的方法的参数。
//
// 类型参数:
// T:
// 此委托封装的方法的参数类型。此类型参数是逆变。即可以使用指定的类型或派生程度更低的类型。有关协变和逆变的更多信息,请参见泛型中的协变和逆变。
public delegate void Action<in T>(T obj);

Func<T, TResult>

关于Func<T, TResult> 委托,和  Action<T> 委托的区别最大点在于Func<T, TResult>支持返回类型,刚才我们看了 Action<T> 以后会觉得  Action<T>  只能用于void方法,那么如果方法返回int, Action<T> 是不是就不能用了?对的,不能用了。

Func<T,TResult> 的表现形式分为以下几种:

1。Func<T,TResult>

2。Func<T,T1,TResult>

3。Func<T,T1,T2,TResult>

4。Func<T,T1,T2,T3,TResult>

5。Func<T,T1,T2,T3,T4,TResult>

其实以上的几种表现形式就是Func<T,TResult>的几种重载,最多支持四个参数的重载,分别说一下各个参数的意义,TResult表示 委托所返回值 所代表的类型, T,T1,T2,T3,T4表示委托所调用的方法的参数类型,

以下是使用示例:

  /*
使用普通委托和泛型委托同样完成一个返回值为string,参数为int方法的委托调用
*/
delegate string DisplayMessage(int message);
static void Main(string[] args)
{
DisplayMessage messageTarget;
messageTarget = Kuadi;
Console.WriteLine(messageTarget());
//Func<T,TResult>
Func<int,string> messageTarget1;
messageTarget1 = Kuadi;
Console.WriteLine(messageTarget1());
}
public static string Kuadi(int zhong) {
if (zhong == )
return "你的快递";
else
return "没有你的货";
}

可以看的出来,泛型委托实际上比起普通委托最大好处就是可以少些很多代码,在以后的代码中可以用泛型委托完成的就不需要使用普通委托去完成,刚才文章中提到了一个委托在linq中得使用,那么linq中如何体现的Action<T> 泛型委托和 Func<T, TResult>泛型委托的呢

Linq中的泛型委托使用

namespace System.Linq
{
public static class Enumerable
{
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
}
}

由于Linq中的方法实在有点多,今天我们只看一下Where,当然具体实现是看不到,但是我们在这串代码中却看到了一个身影Func<TSource, bool>这实际上涉及了linq的内部另一个方法的调用,这串代码所做的事就是把条件作为一个参数传给predicate调用其内部方法,最终返回一个bool值。

当然了委托用在Liqn中不只是这么一个地方,还有很多地方都用到了委托,感兴趣的小伙伴可以研究一下,委托在LInq中的使用