• 委托,不知道你是否有也这样理解(二)


    目录

    • 泛型委托
    • 简化语法
    • 委托与反射

    相关文章链接:

    事件,你是否也这样理解 

    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);
  • 相关阅读:
    JSON数据格式
    AJAX入门
    SpringMVC如何处理JSON数据和运行流程
    SpringMVC视图解析器与数据类型转换
    SpringMVC入门——基础知识
    SpringMVC自定义拦截器与异常处理
    SpringMVC实现文件的上传和下载
    Eclipse中安装Springtools插件的步骤
    SpringMVC实现员工信息的增删改查
    文件的上传与下载
  • 原文地址:https://www.cnblogs.com/sunchong/p/4445981.html
Copyright © 2020-2023  润新知