委托,不知道你是否有也这样理解(二)
目录
- 泛型委托
- 简化语法
- 委托与反射
相关文章链接:
事件,你是否也这样理解
http://www.cnblogs.com/sunchong/p/sunchong.html
委托,你是否也这样理解(一)
http://www.cnblogs.com/sunchong/p/3480612.html
一、泛型委托
我们知道泛型能够提高效率,避免代码重复,灵活。
C#提供了无返回值的泛型委托:Action
public delegate void Action<in T>(T obj);
从上我们看到,输入参数是obj,无返回值。T是泛型占位符,输入参数类型并可以协变。
像这样的委托c#为我们提供了16个,可以传递1~16个输入参数。
C#也提供了有返回值的泛型委托:Func
public delegate TResult Func<in T, out TResult>(T arg);
可以协变的输入参数arg,逆变的返回参数TResult。
这样的泛型委托也是16个,也可以传递1~16个输入参数。外加一个返回参数。返回参数类型位于泛型占位符<in T,inT1,in T2,...,out TResult>最后一个参数TResult。
二、简化语法
1、使用ThreadPool
public void PutMsg() { System.Threading.ThreadPool.QueueUserWorkItem(DelegateTest.PutMsg,"K1"); }
细看一下定义:
public static bool QueueUserWorkItem(WaitCallback callBack, object state);
public delegate void WaitCallback(object state);
很显然,WaitCallback是一个又一个输入参数并无返回值的委托,而参数state就是方法需要传入的参数。
这样的方式有局限性,因为必须是一个输入参数并无返回值。
三、使用Lambda表达式
public void PutMsg() { System.Threading.ThreadPool.QueueUserWorkItem(msg=>Console.WriteLine(msg.ToString()),"K1"); }
编译器会为我们自动创建一个私有方法,这个方法名我们不会知道,因为编译器会根据他自己的规则自动生成。
我们也会将这样的方法称之为匿名方法。传递一个Object类型的参数,在=>后面的就是方法体。通过IL就会看到生成的代码。。
[CompilerGenerated] private static void <PutMsg>b__0(object msg) { Console.WriteLine(msg.ToString()); }
上面就是自己本地的IL代码,我们可以看到我们之前定义的msg和=>的方法体。此外还有一个特性[CompilerGenerated],这说明此特性是编译器生成的代码,不是我们自己写的。
四、局部变量无需包装到类中就可以传递给回调方法
public class AClass { public static void UsingLocalVariablesInTheCallbackCode(Int32 numToDo) { Int32[] squares = new Int32[numToDo]; System.Threading.AutoResetEvent done = new System.Threading.AutoResetEvent(false); for (int n = 0; n < squares.Length; n++) { System.Threading.ThreadPool.QueueUserWorkItem(obj => { int num = (int)obj; squares[num] = num * num; if (System.Threading.Interlocked.Decrement(ref numToDo) == 0) { done.Set(); } }, n); } done.WaitOne(); } }
首先大体分析一下,在这个方法中,有一个参数:numToDo,两个局部变量:squares,done。关键是下面这个Lambda方式的回调函数,而我们知道使用Lambda就类似又构造一个方法。现在的问题是,通过Lamdba方式生成的方法引用了在UsingLocalVariablesInTheCallbackCode(Int32 numToDo)方法定义的局部变量。我们知道同一个类中的两个方法,一个方法无法直接引用另一个方法的局部变量。那为什么以上可以直接引用?而且还让我们感觉用得理所当然。好吧,编译器确实又为我们做了很多工作,如果我们想让一个方法引用到另一方法中的局部变量,那就将这些局部变量打包到一个类中,通过传递此类对参数进行赋值和取值。
四、委托与反射
一般情况下我们会知道回到函数的参数个数和类型,但是如果我们不确定这些,那就通过反射让编译器来生成我们所需要的。
C#的Delete类为我们提供了委托反射(下面只是其中一个),通过传递委托类型和注册的方法名,对方法进行注册。
public static Delegate CreateDelegate(Type type, MethodInfo method);
通过DynamicInvoke来进行调用。
public object DynamicInvoke(params object[] args);

【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· 赶AI大潮:在VSCode中使用DeepSeek及近百种模型的极简方法
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地