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


    目录

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

    相关文章链接:

    事件,你是否也这样理解 

    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);
  • 相关阅读:
    PHP实现git部署的方法教程
    windows下php7.1安装redis扩展以及redis测试使用全过程
    win7下php7.1运行getenv('REMOTE_ADDR')fastcgi停止运行
    CGI与FastCGI
    Laravel 单设备登录
    Laravel 登录后清空COOKIE 方法
    PHP进阶与redis锁限制并发访问功能示例
    微信开放平台开发——网页微信扫码登录(OAuth2.0)
    laravel 项目本地版本为5.5,线上mysql 为5.7.21版本,执行严格模式
    mysql中bigint、int、mediumint、smallint与tinyint的取值范围
  • 原文地址:https://www.cnblogs.com/sunchong/p/4445981.html
Copyright © 2020-2023  润新知