zoukankan      html  css  js  c++  java
  • Delegate

        • 1.什么是委托
        • 2.委托概述
        • 3.声明委托类型
        • 4.创建委托对象
        • 5.给委托赋值
        • 6.组合委托
        • 7.为委托添加/移除方法
        • 8.调用委托
        • 9.委托的示例
        • 10.调用带返回值的委托
        • 11.调用带引用参数的委托
        • 12.匿名方法
          • 12.1 使用匿名方法
          • 12.2 匿名方法的语法
            • 12.2.1 返回类型
            • 12.2.2 参数
            • 12.2.3 params参数
        • 13.Lambda表达式
        • 14.常见泛型委托
          • 14.1 Action
          • 14.2 Func
          • 14.3 Predicate

    1.什么是委托

    可以认为委托是持有一个或多个方法的对象,此对象可以执行它所“持有”的方法。

    delegate void Del(int value);
    class Program
    {
        static int a = 1;
        static void Up(int v)
        {
            Console.WriteLine($"{a + v}");
        }
        static void Down(int v)
        {
            Console.WriteLine($"{a - v}");
        }
        static void Main()
        {
            Del del1 = new Del(Up);
            Del del2 = new Del(Down);
            del1(1);
            del2(1);
            Console.ReadKey();
        }
    

    output

    2
    0
    

    2.委托概述

    使用委托与类的比较,入下图:
    image
    可以把委托看作是包含有序方法列表的对象,这些方法具有相同的签名和返回类型:

    • 方法的列表称为调用列表
    • 委托保存的方法可以来自任何类或结构,只有匹配一下两点:
      • 委托的返回类型
      • 委托的签名(包括ref和out修饰符)
    • 调用列表中的方法可以是实例方法也可以是静态方法
    • 在调用委托时,会执行其调用列表中的所有方法
      image

    3.声明委托类型

    委托类型定义了委托对象调用列表中允许的方法的形式,如下示例代码声明了委托类型:

    delegate void MyDel( int x ); // delegate为关键字,void为返回类型,MyDel为委托类型名,int为签名
    

    委托声明与方法声明的不同:

    • 以delegate关键字开头
    • 没有方法主体
    • 不需要在类内部声明,因为它是类型声明

    4.创建委托对象

    委托类型的变量声明如下:

    MyDel delVar;
    

    有两种创建委托对象的方式,第一种是使用new运算符, new运算符的操作数组成如下:

    • 委托类型名
    • 一组圆括号,其中包含作为调用列表中的第一个成员的方法的名字
    delVar = new MyDel(Class1.Method1);
    

    还可以使用以下快捷语法创建委托对象:

    delVar = Class1.Method1;
    

    5.给委托赋值

    由于委托时引用类型,可以通过赋值来改变包含在委托变量中的引用,旧的委托对象会被垃圾回收器回收。

    MyDel delVar;
    delVar = Class1.Method1;
    delVar = Class1.Method2; // Class1.Method1将会被GC
    

    6.组合委托

    委托可以调用额外的运算符来“组合”。

    MyDel delA = Class1.Method1;
    MyDel delB = Class1.Method2;
    MyDel delC = delA + delB; // 组合调用列表
    

    image


    7.为委托添加/移除方法

    使用+=运算符为委托添加方法:

    MyDel delA = Class1.Method1; // 创建并初始化
    delA = Class2.Method2; // 增加方法
    delA = StaticClass.StaticMethod; // 增加方法
    

    由于委托是不可变的,所以每添加一个方法其实是创建了一个新的委托。 使用-=运算符为委托移除方法:

    delA -= Class2.Method2; // 从委托移除方法
    

    移除一个方法同样是创建了一个新的委托。 移除委托时的注意事项:

    • 如果再调用列表中有多个相同的方法,将从列表最后开始搜索,并移除第一个匹配方法
    • 试图删除委托中不存在的方法没有效果
    • 试图调用空委托会抛出异常,若调用列表为空,则委托是null

    8.调用委托

    可以向调用方法一样简单的调用委托。

    Mydel delVar = inst.MyM1;
    delVar += SCl.m3;
    delVar += X.Act;
    ...
    delVar(55);
    

    在使用参数调用委托时会使用相同的参数值(如55)。


    9.委托的示例

    delegate void PrintFunction();
    class Test
    {
        public void Print1()
        {
            Console.WriteLine("Print1 -- instance");
        }
        public static void Print2()
        {
            Console.WriteLine("Print2 -- static");
        }
    }
    class Program
    {
        static void Main()
        {
            Test t = new Test();
            PrintFunction pf = t.Print1;
            pf += Test.Print2;
            pf += t.Print1;
            pf += Test.Print2;
            if(null!=pf)
            {
                pf();
            }
            else
            {
                Console.WriteLine("Delegate is empty");
            }
            Console.ReadKey();
        }
    }
    

    output

    Print1 -- instance
    Print2 -- static
    Print1 -- instance
    Print2 -- static
    

    10.调用带返回值的委托

    delegate int MyDel();
    class MyClass
    {
        int value = 5;
        public int Add2()
        {
            value += 2;
            return value;
        }
        public int Add3()
        {
            value += 3;
            return value;
        }
    }
    class Program
    {
        static void Main()
        {
            MyClass mc = new MyClass();
            MyDel md = mc.Add2;
            md += mc.Add3;
            md += mc.Add2;
            Console.WriteLine($"value = {md()}");
            Console.ReadKey();
        }
    }
    

    output

    value = 12
    

    最后一个方法执行的返回值是委托的返回值。


    11.调用带引用参数的委托

    在调用委托列表中的下一个方法时,参数的新值回传给下一个方法

    delegate void MyDel(ref int x);
    class MyClass
    {
        public void Add2(ref int x) { x += 2; }
        public void Add3(ref int x) { x += 3; }
        static void Main()
        {
            MyClass mc = new MyClass();
            MyDel md = mc.Add2;
            md += mc.Add3;
            md += mc.Add2;
            int x = 5;
            md(ref x);
            Console.WriteLine($"value = {x}");
            Console.ReadKey();
        }
    }
    

    output

    value = 12
    

    12.匿名方法

    匿名方法是在初始化委托时内联声明的方法。

    12.1 使用匿名方法

    • 声明委托变量时作为初始化表达式
    • 组合委托时在赋值语句的右边
    • 为委托增加事件时在赋值语句的右边

    12.2 匿名方法的语法

    匿名方法表达式的语法包含以下组成部分:

    • delegate类型关键字
    • 参数列表,无参可省略
    • 语句块,包含匿名方法的代码
    delegate ( Parameters ) { ImplementationCode }
    
    12.2.1 返回类型

    若委托的返回类型为int,则匿名方法中也应返回int。

    delegate int Del(int n);
    static void Main()
    {
        Del d = delegate(int x) { return x + 20; } // 返回一个整型值
    }
    
    12.2.2 参数

    除了数组参数,匿名方法的参数列表必须与委托有以下匹配:

    • 参数数量
    • 参数类型及位置
    • 修饰符 以下两个情况都满足可以简化匿名方法的参数列表:
    • 委托的参数列表不包含任何out参数
    • 匿名方法不使用任何参数
    delegate void Del(int x);
    Del d = delegate
            {
                PrintMessage();
                CleanUp();
            };
    
    12.2.3 params参数

    如果委托声明的参数列表包含params参数,那么匿名方法的参数列表将忽略params关键字:

    delegate void Del(int x, params in[] y);
    Del d = delegate(int x, int[] y){...};
    
    delegate void MyDel(int x, params int[] y);
    class MyClass
    {
        static void Main()
        {
            MyDel md = delegate (int x, int[] y)
            {
                foreach(var i in y)
                {
                    Console.WriteLine(i);
                }
            };
            md(1, 2, 3, 4);
            Console.ReadKey();
        }
    }
    

    output

    2
    3
    4
    

    13.Lambda表达式

    使用Lambda表达式创建委托:

    MyDel del = delegate(int x) {return x + 1;}; // 匿名方法
    MyDel newdel = (int x) => {return x + 1;}; // Lambda表达式
    

    Lambda表达式的简化规则:

    • 编译器可从委托声明中得到委托参数的类型(ref和out参数须注明类型)
      • 带有类型的参数列表称为显示类型
      • 省略类型的参数列表称为隐式类型
    • 如果只有一个隐式类型参数,则可以省略圆括号
    • Lambda允许表达式主体是语句块或表达式 Lambda表达式的语法演示如下:
    (参数,参数)
    (参数)
    参数
    ()
    =>{语句}
    表达式

    Lambda表达式的语法由Lambda运算符和左边的参数部分以及右边的Lambda主体构成。


    14.常见泛型委托

    14.1 Action

    Action<>委托可以拥有n个参数(0-16),无返回值。

    class Program
    {
        static void Method1()
        {
            Console.WriteLine("without any parameter");
        }
        static void Method2(int i)
        {
            Console.WriteLine($"the int is {i}");
        }
        static void Method3(string s, double d)
        {
            Console.WriteLine($"the string is {s}, the double is {d}");
        }
        static void Main()
        {
            Action A1 = Method1;
            Action<int> A2 = Method2;
            Action<string, double> A3 = Method3;
            A1();
            A2(1);
            A3("hello", 3.14);
            Console.ReadKey();
        }
    }
    

    output

    without any parameter
    the int is 1
    the string is hello, the double is 3.14
    

    14.2 Func

    Func<>委托可以拥有n个参数(1-16),类型参数中的最后一个作为返回值类型。因此类型参数不能为空,至少有一个返回类型。

    class Program
    {
        static int Method1(int i)
        {
            return i * 10;
        }
        static string Method2(int a, double d)
        {
            return (a + d).ToString();
        }
        static void Main()
        {
            Func<int, int> F1 = Method1;
            Func<int, double, string> F2 = Method2;
            Console.WriteLine($"{F1(10)}");
            Console.WriteLine($"{F2(1, 3.14)}");
            Console.ReadKey();
        }
    }
    

    output

    100
    4.14
    

    14.3 Predicate

    Predicate<>委托拥有一个参数,其返回值为bool型。

    class Program
    {
        static bool Method(int i)
        {
            return i > 0 ? true : false;
        }
        static void Main()
        {
            Predicate<int> P = Method;
            Console.WriteLine(P(10));
            Console.ReadKey();
        }
    }
    

    output

    True
    

    通过匿名方法使用Predicate<>,

    class Program
    {
        static void Main()
        {
            var anomynous = new Predicate<int>(delegate (int i) { return i > 0 ? true : false; });
            Console.WriteLine(anomynous(1));
            Console.ReadKey();
        }
    }
    

    output

    True
  • 相关阅读:
    velocity导出word报错解决
    Java解析网段下包含的所有IP地址
    ORACLE中的DECODE函数
    td标签内的内容过长导致的问题的解决办法
    android 知识点
    geekNews 学习总结
    android 操蛋的gradle
    rxJava rxandroid 学习
    线程池ThreadPoolExecutor
    j2ee tomcat 部署学习
  • 原文地址:https://www.cnblogs.com/jizhiqiliao/p/10649160.html
Copyright © 2011-2022 走看看